Adding a New UIViewController – RubyMotion

Adding a New UIViewController

As the name suggests, UIViewControllers are objects that control a view. The UIViewController object stores the UIView it manages inside the view attribute. However, we generally don’t use addSubview: to add this particular view to the screen; instead, various methods will often take the entire UIViewController object and adjust the view as necessary before adding it to a hierarchy.

Let’s get started with a small project to see how UIViewController works, and you’ll see what I mean. We’ll create an app showing different ways to explore colors, specifically, motion create ColorViewer.

First we make the ./app/controllers directory (mkdir ./app/controllers). This is where we’ll keep all of our controller classes. When building production-level apps, you should also add views and models subdirectories, but we won’t be needing those right now.

Then we add a colors_controllerrb file in controllers. This will be our custom UIViewController subclass that’s presented to the user. We’ll start by setting its superclass and adding one short method.

 class​ ColorsController < UIViewController
 def​ viewDidLoad
 super
 
  self.view.backgroundColor = UIColor.whiteColor
 
  @label = UILabel.alloc.initWithFrame(CGRectZero)
  @label.text = ​"Colors"
  @label.sizeToFit
  @label.center =
  [self.view.frame.size.width / 2,
  self.view.frame.size.height / 2]
  @label.autoresizingMask =
  UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin
  self.view.addSubview(@label)
 end
 end

Subclassing UIViewController always involves overriding viewDidLoad. This method is called right after our controller’s view has been created and is where we do whatever custom setup is necessary. For now, we just set the view’s background color, add a label, and call it a day.

viewDidLoad is one of the view life-cycle methods. Every controller’s view goes through several stages: creation, appearance, disappearance, and destruction. You can add custom behaviors at each point using the corresponding life-cycle methods, but the most common is viewDidLoad.

Now that we have our controller, open our AppDelegate. We’re going to create a UIWindow just like we did in the previous chapter, except we’re now going to use the rootViewController= method instead of addSubview:.

 class​ AppDelegate
 def​ application(application, didFinishLaunchingWithOptions​:launchOptions​)
  @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
  @window.makeKeyAndVisible
 
  @window.rootViewController =
  ColorsController.alloc.initWithNibName(​nil​, ​bundle: ​​nil​)
 
 true
 end
 end

rootViewController= will take the UIViewController and adjust the view’s frame to fit the window. This lets us write our controller without hard-coding its size, making our controller reusable to other containers. As we said earlier, methods in which you pass a UIViewController are very common, as we’ll soon see.

We instantiate UIViewControllers with initWithNibName:bundle:. This method can be used to load a controller from a NIB/XIB file created using Xcode’s Interface Builder, but in this case, we passed nil, meaning the controller will be created programatically.[13]

initWithNibName:bundle: is the designated initializer of UIViewController. Whenever you want to create a controller, you must call this method at some point, either directly or inside the definitions of your custom initializers (such as controller.initWithSome:property:).

Let’s run our app and check it out:

As we saw in Making Shapes and Colors, a few addSubview:s could have given us the same result, but using controllers creates a view that can easily fit into different containers. In fact, we’re going to do just that with UINavigationController in Using Multiple Controllers with UINavigationController.