A UIViewController->URL router.
@router.map("profile/:id", ProfileController)
# Later on...
# Pushes a ProfileController with .initWithParams(:id => 189)
@router.open("profile/189")
Why is this awesome? Because now you can push any view controller from any part of the app with just a string: buttons, push notifications, anything.
gem install routable
And now in your Rakefile, require routable
:
$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'
require 'routable'
Motion::Project::App.setup do |app|
...
end
For every UIViewController you want routable with :symbolic
params, you need to define .initWithParams({})
.
class ProfileController < UIViewController
attr_accessor :user_id
def initWithParams(params = {})
init()
self.user_id = params[:user_id]
self
end
end
Here's an example of how you could setup Routable for the entire application:
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
@window.makeKeyAndVisible
# Make our URLs
map_urls
# .open(url, animated)
if User.logged_in_user
@router.open("menu", false)
else
@router.open("login", false)
end
true
end
def map_urls
@router = Routable::Router.router
@router.navigation_controller = UINavigationController.alloc.init
# :modal means we push it modally.
@router.map("login", LoginController, modal: true)
# :shared means it will only keep one instance of this VC in the hierarchy;
# if we push it again later, it will pop any covering VCs.
@router.map("menu", MenuController, shared: true)
@router.map("profile/:id", ProfileController)
# :resets will reset the navigation stack with the target view controller
@router.map("messages", MessagesController, resets: true)
@router.map("message/:id", MessageThreadController)
# can also route arbitrary blocks of code
@router.map("logout") do
User.logout
end
@router.map("logout/:id") do |params|
User.logout(params[:id])
end
@window.rootViewController = @router.navigation_controller
end
end
If you need to configure a view controller before the router navigates to it, use a block:
# Configure and push an ImageEditorController
BW::Device.camera.any.picture(media_types: [:movie, :image]) do |result|
router.open('editor') do |controller|
controller.image = result[:original_image]
end
end