jamonholmgren / ProMotion

ProMotion is a RubyMotion gem that makes iPhone development less like Objective-C and more like Ruby.
MIT License
1.26k stars 148 forks source link

Instagram style TabBar presenting a modal view #549

Closed ghost closed 9 years ago

ghost commented 10 years ago

I have been messing around a lot trying to get this to work by implementing UITabBarViewController delegate methods, but no luck. Trying to follow this guide: https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar But I am having trouble making things work with PM. Any ideas or advice?

Here is my 'just trying things out' code. Nothing special, but maybe a starting point to see what I am doing wrong.

class AppDelegate < PM::Delegate
  # piechart code http://lepetit-prince.net/ios/?p=1510

  include CDQ

  status_bar true, animation: :none
  tint_color UIColor.redColor

  def on_load(app, options)
    return true if RUBYMOTION_ENV == "test"
    cdq.setup

    hs = HomeScreen.new(nav_bar: true)
    ns = NewScreen.new(nav_bar: true, modal: true)
    gs = GroupScreen.new(nav_bar:true)

    open_tab_bar hs, ns, gs

    tab_bar.delegate = self
  end

  def tabBarController(tabBarController, shouldSelectViewController:viewController)
    # puts "shouldSelect"
    # puts viewController.title

    if viewController.title == "NewIOU"
      ns = NewScreen.new(nav_bar: true, modal: true)
      ns.hidesBottomBarWhenPushed = true
      ns.modalPresentationStyle = UIModalPresentationFormSheet
      ns.modalTransitionStyle = UIModalTransitionStyleCoverVertical
      ns.definesPresentationContext = true
      ns.providesPresentationContextTransitionStyle = true
      open NewScreen.new(nav_bar: true), animated: true
      return false
    end
    true
  end

  def tabBarController(tabBarController, didSelectViewController:viewController)
    # puts "didSelect"
    # puts viewController.title
  end
end
jamonholmgren commented 10 years ago

@stephenlaughton Thanks for checking out PM! Your example is working for me. When I enable the puts calls I get this when tabbing around:

shouldSelect
NewScreen
didSelect
NewScreen
shouldSelect
GroupScreen
didSelect
GroupScreen

What's not working for you?

ghost commented 10 years ago

@jamonholmgren Thanks for the reply! The more I am looking at the power of PM the more I am loving it.

There are two issues (and I didn't really outline them very well in the initial post): 1) The NewScreen in:

    hs = HomeScreen.new(nav_bar: true)
    ns = NewScreen.new(nav_bar: true, modal: true)
    gs = GroupScreen.new(nav_bar:true)

    open_tab_bar hs, ns, gs

Doesn't open with any sort of animation and also doesn't dismiss with any sort of animation... which is why I tried to plug into the TabBarViewController to further customize the behaviour and load the NewScreen vc manually. But even then there is no animation.

2) Once I am in NewScreen, if I got there from the delegate method there is no way to dismiss the vc, and if I get there from the standard 'open_tab_bar hs, ns, gs' approach it doesn't dismiss with animations.

I guess I am getting a 'pseudo modal' behaviour with what I have now (if you comment out the whole delegate method), but without the animations it doesn't feel modal. Ideally I want to clone Instagram behaviour where NewScreen drops down modally when the centre tab is selected. I have looked through the TabBar module and maybe I should try modifying that? But I figured I would ask here first to rule out any obvious solutions I can't see.

jamonholmgren commented 10 years ago

Ah, @stephenlaughton, that's a bit more involved! I unfortunately don't have time to step you through it at the moment. Keep in mind that calling open in your AppDelegate will essentially blow away your tab bar (they're both opened "at root"). Instead, you can call tab_bar.open_tab "Something", but getting the animations to work is a bit more involved.

I'd encourage you to look in lib/ProMotion/tabs/tabs.rb -- it's a pretty small module and you should be able to understand what's happening. This module is mixed into PM::Delegate as well as PM::Screen.

ghost commented 10 years ago

Looking around it seems like it might be possible to modify the screen_navigation.rb....

def open_screen(screen, args = {})
      args = { animated: true }.merge(args)

      # Apply properties to instance
      screen = set_up_screen_for_open(screen, args)
      ensure_wrapper_controller_in_place(screen, args)

      opened ||= open_in_split_screen(screen, args) if self.split_screen
      opened ||= open_root_screen(screen) if args[:close_all]
      opened ||= present_modal_view_controller(screen, args) if args[:modal]
      opened ||= open_in_tab(screen, args[:in_tab]) if args[:in_tab]
      opened ||= push_view_controller(screen, self.navigationController, !!args[:animated]) if self.navigationController
      opened ||= open_root_screen(screen.navigationController || screen)
      screen
    end

Would this be a good or bad place to start? I have moved on without PM for now, just doing everything by hand, but I would like to mess around after my app is complete and see if I could make PM work.

jamonholmgren commented 10 years ago

If you do start there, run your proposed changes by us in this issue before you get too far. I want to make sure you're not wasting your time if we don't like the direction it's headed. :)

chrise86 commented 9 years ago

How did you get on with this @stephenlaughton ?

ghost commented 9 years ago

Hey @chrise86 I ended up subclassing UITabBarController with 3 viewcontrollers, made the middle one a sort of placeholder (to maintain a uniform look) and implementing the tabBarController:didSelectViewController: method to push a modal viewcontroller whenever the centre tabbaritem was selected. I will definitely mess around with a ProMotion version of this when I have more time, but for now the old way is working great.