Navigation
In Android development, screens are separated as activities, so we had to jump through some hoops to pass information between activities. In iOS development, life-cycle concepts apply to the whole application, not its individual screens / activities. Two pages back I quoted from the UIWindow class reference which says:
To change the content your app displays, you can change the window’s root view; you don’t create a new window
In our AppDelegate
we declared the window's root view by setting the rootViewController
property. So let's learn how to navigate between different views.
New Controller
First let's see what happens if I have my send_message
method change the root view of
the window to a blank one without any other modifications.
def send_message
window.rootViewController = UIViewController.alloc.init
end
You should get a completely blank screen.
New View
A quick look at the UITextView docs tells us that if all we want to do is display some text, we just need to create a text field with a frame and add text to it.
text_view_frame = CGRectMake(15, 80, 265, 40)
text_view = UITextView.alloc.initWithFrame(text_view_frame)
text_view.text = text_field.text
You can add other nice things like a bigger font, making the view non-editable and such but I'll leave that up to you to play with the API and get a text field that you're happy with.
Once you have a view like this we can add it as a subview of our new UIViewController
and now the button will take us to a new screen:
new_view_controller = UIViewController.alloc.init
new_view_controller.title = 'Check Text'
new_view_controller.view.backgroundColor = UIColor.whiteColor
text_view_frame = CGRectMake(15, 80, 265, 40)
text_view = UITextView.alloc.initWithFrame(text_view_frame)
text_view.text = text_field.text
text_view.font = UIFont.systemFontOfSize(25)
text_view.editable = false
new_view_controller.view.addSubview(text_view)
window.rootViewController = new_view_controller
Warning -
See what happens if you use view_controller.view = text_view
instead of adding it as a subview. You should find that the frame's position / bounds are ignored. Be warned that controllers like this have their own views and you shouldn't mess with them.
I left this code as one big send_message
method, but feel free to be a little tidier with how you handle the two screens in the app. I suspect in a real app this would be a point where you might want to break out into multiple files, controllers, etc. but I'm going to avoid that to keep pace.
Navigation
The last thing we need to do, is add back the navigation controller that was originally given to us as boiler plate code. If you've been struggling to get a solid picture in your mind of how these views and controllers are interacting here's the iOS guide for you.
The idea is that a navigation controller is managing a stack of view controllers. You pick one to be the root of the stack and the rest go on top. So let's call the view that has a text field and a button our "home view" and then let's use it to init
a navigation controller.
I'll go ahead and show most of the class: pay attention to all the places I renamed the controller to home_controller
and don't forget to make the nav_controller
the root view
controller of the window.
attr_reader :nav_controller, :home_controller, :window, :text_field, :button
def application(application, didFinishLaunchingWithOptions: launchOptions)
create_controllers
create_window
create_text_field
create_button
true
end
def create_controllers
@home_controller = UIViewController.alloc.init
home_controller.title = 'FirstApp'
home_controller.view.backgroundColor = UIColor.whiteColor
@nav_controller = UINavigationController.alloc.initWithRootViewController(home_controller)
end
def create_window
screen_frame = UIScreen.mainScreen.bounds
@window = UIWindow.alloc.initWithFrame(screen_frame)
window.rootViewController = nav_controller
window.makeKeyAndVisible
end
def create_text_field
text_field_frame = CGRectMake(15, 80, 265, 40)
@text_field = UITextField.alloc.initWithFrame(text_field_frame)
style_text_field
home_controller.view.addSubview(text_field)
end
def create_button
@button = UIButton.buttonWithType(UIButtonTypeSystem)
style_button
home_controller.view.addSubview(button)
end
Push and Pop
With a navigation controller in place, and a view controller set as its root, all we need
to do now is just have the send_message
method push a new controller onto the navigation stack. If you read the UINavigationController
docs you'll see that the methods for this are push and pop. We'll just use push
def send_message
new_view_controller = UIViewController.alloc.init
new_view_controller.title = 'Check Text'
new_view_controller.view.backgroundColor = UIColor.whiteColor
text_view_frame = CGRectMake(15, 80, 265, 40)
text_view = UITextView.alloc.initWithFrame(text_view_frame)
text_view.text = text_field.text
text_view.font = UIFont.systemFontOfSize(25)
text_view.editable = false
new_view_controller.view = text_view
nav_controller.pushViewController(new_view_controller, animated: true)
end
And voila! You now have your first app. It can take input from the user and navigate between view controllers.
Conclusion
I hope in these lessons you've learned a lot. In the future we (hopefully) won't be doing too much of this kind of "low level" programming thanks to some nice gems and other tools that abstract some of this stuff away. But I'm confident that if you spend time in these lessons learning the basics of RubyMotion development, you'll be better able to tackle the problems unique to your programming puzzle.
Next up, let's learn about the other tools that RubyMotion developers use to make writing apps more painless.