Creating Container View Controllers

Post on 15-May-2015

44,123 views 1 download

Tags:

description

Presentation given at 2012 360iDev Conference.

transcript

http://bobmccune.com

Creating Container View

Controllers

Bob McCuneAbout...

‣MN Developer and Instructor‣Owner of TapHarmonic, LLC.‣Founded Minnesota CocoaHeads in 2008

What will I learn?Agenda

‣View Controller Overview‣Custom Containers Before iOS 5‣ iOS 5’s View Controller Containment API‣Custom Container Demo

View ControllerOverview

View Controller OverviewWhat is a View Controller?

‣Focal point of most iOS app development‣Key Responsibilities:‣De!nes the application work"ow‣Manages a view hierarchy‣ Programmatically

‣ NIB and/or Storyboard

‣Plays the MVC “Controller” role...

View Controller: The “C” in MVCUnderstanding MVC

Controller

View

User ActionsUpdate State

Model

View Controller: The “C” in MVCUnderstanding MVC

Controller

View

Update UIState Changed

Model

Core iOS Design PatternMVC Bene!ts

‣Clean separation of concerns‣Simpli!es development‣Provides for greater reusability‣ Improves quality

‣Allows us to standardize the behavior and responsibilities at each tier

Standardized BehaviorUIViewController Lifecycle

‣ Rotation Callbacks- (void)willRotateToInterfaceOrientation:- (void)willAnimateRotationToInterfaceOrientation:- (void)didRotateFromInterfaceOrientation:

‣ Loading Callbacks- (void)viewDidLoad;- (void)viewDidUnload;

‣ Appearance Callbacks- (void)viewWillAppear:- (void)viewDidAppear:- (void)viewWillDisappear:- (void)viewDidDisappear:

Container vs ContentView Controller Types

Container Controllers‣ Manages a hierarchy of child view controllersUITabBarControllerUINavigationControllerUISplitViewController

Content Controllers‣ Manage the individual screens within an app‣ Can be used in multiple presentation contexts‣ Manages a “screenful of content”

Seems reasonable...Screenful of Content

Still reasonable?Screenful of Content

What’s a screenful?UISplitViewController

One Screen, Multiple ControllersWhy Create Custom Containers?

‣Aesthetics‣Create a custom application "ow

Custom ContainersThe heartbreaking true story

 Pre  -­  iOS  5

Faulty AssumptionsCustom Containers

Static  Logo

Faulty AssumptionsCustom Containers

Static  Logo

Faulty AssumptionsCustom Containers

Static  Logo

Faulty AssumptionsCustom Containers

Static  Logo

No you can’t!

Custom Container FailWhat’s the problem?

‣Broken View Controller Hierarchy

‣ Rotation Callbacks- (void)willRotateToInterfaceOrientation:- (void)willAnimateRotationToInterfaceOrientation:- (void)didRotateFromInterfaceOrientation:

‣ Appearance Callbacks- (void)viewWillAppear:- (void)viewDidAppear:- (void)viewWillDisappear:- (void)viewDidDisappear:

Ugly OptionsHow do you !x it?

Create a MonstrosityControllerNot practical

Create non-UIViewController controllersNot scalable

Create container and forward callbacksIncomplete and ugly

View Controller Containment

View vs View ControllerObject Hierarchies

Window

Root View

Tab Bar

NavBar

Segmented

View Hierarchy

View vs View ControllerObject Hierarchies

View Controller Hierarchy

UITabBarController

UINavigationController

ContentViewController

Simple, but subtleView Controller Containment

Child View Controller Callbacks- (void)willMoveToParentViewController:(UIViewController *)parent;- (void)didMoveToParentViewController:(UIViewController *)parent;

Adding and removing child controllers- (void)addChildViewController:(UIViewController *)controller;- (void)removeFromParentViewController;

Accessing the children@property(nonatomic,readonly) NSArray *children;

Adding a Child View ControllerContainment API Usage

[self addChildViewController:controller];[self.view addSubview:controller.view];[controller didMoveToParentViewController:self];

ParentViewController

ChildViewController view

view

willMove

Adding a Child View ControllerContainment API Usage

[self addChildViewController:controller];[self.view addSubview:controller.view];[controller didMoveToParentViewController:self];

ParentViewController

ChildViewController view

view

didMove

Adding a Child View ControllerContainment API Usage

[self addChildViewController:controller];[self.view addSubview:controller.view];[controller didMoveToParentViewController:self];

ParentViewController

ChildViewController view

view

willMove

Removing a Child View ControllerContainment API Usage

ParentViewController

ChildViewController view

view

[controller willMoveToParentViewController:nil];[controller.view removeFromSuperview];[controller removeFromParentViewController];

Removing a Child View ControllerContainment API Usage

ParentViewController

ChildViewController view

view

[controller willMoveToParentViewController:nil];[controller.view removeFromSuperview];[controller removeFromParentViewController];

didMove

Removing a Child View ControllerContainment API Usage

ParentViewController

ChildViewController view

view

[controller willMoveToParentViewController:nil];[controller.view removeFromSuperview];[controller removeFromParentViewController];

Simplifying TransitionsView Controller Transitions

- (void)transitionFromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))block;

‣ Convenience method for view controller transitions‣Optional, but simpli!es and normalizes transitioning

- (void)pushViewController:(UIViewController *)toViewController animated:(BOOL)animated {

UIViewController *fromViewController = [self.stack topObject]; toViewController.view.frame = CGRectMake(width, 0.f, width, height);

[self addChildViewController:toViewController];

NSTimeInterval duration = animated ? 0.3f : 0.f;

[self transitionFromViewController:fromViewController toViewController:toViewController duration:duration options:UIViewAnimationCurveEaseInOut animations:^{ CGRect frame = CGRectMake(-width, 0.f, width, height); fromViewController.view.frame = frame; } completion:^(BOOL complete) { [toViewController didMoveToParentViewController:self]; [self.stack pushObject:toViewController]; }];}

pushViewController:animated:Cloning UINavigationController

popViewControllerAnimated:Cloning UINavigationController

- (UIViewController *)popViewControllerAnimated:(BOOL)animated {

UIViewController *fromViewController = [self.stack popObject]; UIViewController *toViewController = [self.stack topObject];

[fromViewController willMoveToParentViewController:nil];

NSTimeInterval duration = animated ? 0.3f : 0.0f;

[self transitionFromViewController:fromViewController toViewController:toViewController duration:duration options:UIViewAnimationOptionCurveEaseInOut animations:^{ CGRect frame = CGRectMake(width, 0.f, width, height); fromViewController.view.frame = frame; } completion:^(BOOL complete) { [fromViewController removeFromParentViewController]; }]; return fromViewController;}

Fine Tuning ContainmentDisabling Auto Forwarding

- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers { return NO;}

• Control timing of appearance and rotation callbacks• Useful override in complex containment scenarios

Common MistakesAvoiding

Simple API, Common ProblemsCommon Mistakes

‣Outside Callers‣Disobedient Children‣Meddling Parents

Drive-by AdoptionOutside Callers

ModalViewController

ChildViewController

RootViewController

- (IBAction)showModalView:(id)sender { ModalViewController *modalController = [ModalViewController controller]; [self presentViewController:modalController animated:YES completion:nil]; ChildViewController *childController = [ChildViewController controller]; [modalController addChildViewController:childController]; [modalController addSubview:childController.view];}

Parents make the rulesDisobedient Children

- (void)showChildViewController:(UIViewController *)controller { [self addChildViewController:controller];

CustomContainerController

CustomContainerController

OtherViewController

controller.view.frame = CGRectMake(0, 0, 320, 480); [self.view addSubview:controller.view]; [controller didMoveToParentViewController:self];}

- (void)didMoveToParentViewController:(UIViewController *)parent { self.view.frame = CGRectMake(0, 260, 320, 220); [parent.view addSubview:self.view];}

ChildViewController

ChildViewController

Parents make the rulesDisobedient Children

- (void)showChildViewController:(UIViewController *)controller { [self addChildViewController:controller];

CustomContainerController

CustomContainerController

OtherViewController

controller.view.frame = CGRectMake(0, 0, 320, 480); [self.view addSubview:controller.view]; [controller didMoveToParentViewController:self];}

- (void)didMoveToParentViewController:(UIViewController *)parent { self.view.frame = CGRectMake(0, 260, 320, 220); [parent.view addSubview:self.view];}

ChildViewController

ChildViewController

Parents make the rulesDisobedient Children

- (void)showChildViewController:(UIViewController *)controller { [self addChildViewController:controller];

CustomContainerController

OtherViewController

CustomContainerController

[controller didMoveToParentViewController:self];}

ChildViewController

controller.view.frame = CGRectMake(0, 260, 320, 220); [self.view addSubview:controller.view];

Let children be childrenMeddling Parents

ParentViewController

ChildViewController

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration { self.childViewController.button1.frame = // button 1 frame for orientation; self.childViewController.button2.frame = // button 2 frame for orientation; self.childViewController.button3.frame = // button 3 frame for orientation;}

ParentViewController

Let children be childrenMeddling Parents

ParentViewController

ChildViewController

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration { self.button1.frame = // button 1 frame for orientation; self.button2.frame = // button 2 frame for orientation; self.button3.frame = // button 3 frame for orientation;}

ChildViewController

Let children be childrenMeddling Parents

ParentViewController

ChildViewController

Demo

View Controller Containment FTW!Summary

‣Simple, but subtle API. Easy to make mistakes.‣Need to understand UIViewController internals‣Small, but important, enhancements in iOS 6

Resources

Presentation Materialshttp://www.slideshare.net/bobmccune/https://github.com/tapharmonic/

WWDC 2011: Implementing View Controller Containmenthttps://developer.apple.com/videos/wwdc/2011/?id=102

WWDC 2012: The Evolution of View Controllers on iOShttps://developer.apple.com/videos/wwdc/2012/?id=236

BobMcCune.com @bobmccune