ViewController Programming Guide 笔记(二)

Implementing a Container View Controller

容器 view controllers 将许多 view controllers 的内容归并到单独的界面上,容器类 view controllers 通常用于内容导航,如 UINavigationController, UITabBarController, and UISplitViewController

Designing a Custom Container View Controller

容器类 VC内容类 VC 不同之处在于 容器VC 的一部分内容来自于 内容VC,这部分显示内容表现为其他 VC 的 view,且被嵌入进自己的 view 层级中,容器VC会决定这些嵌入 view 的位置和尺寸,但是这些嵌入的 view 仍然被其自身的 VC 所管理。

设计你自己的 容器类VC,需要理解容器和内容 VC 之间的关系,在设计过程中,考虑以下几个问题:

  • 思考容器与其中的内容扮演的角色
  • 有多少内容可以被同时显示
  • 这些子内容的 VC 之间的关系是什么
  • 这些子 VC 如何从容器中添加与移除
  • 这些子 view 的位置和尺寸能否发生变化,当变化发生时,容器该如何对应这些变化
  • 容器能否提供任何装饰性或导航相关的视图
  • 容器与子内容直接的必要通讯是怎样的,容器是否需要将相关通知事件通报给子内容
  • 容器的外观是否可以被定制,如果可以,怎么做?

UIKit 要求你在 容器 VC子 VC 建立正式的父子关系,这种父子关系会确保 子VC 会收到所有相关的系统通知

Configuring a Container in Interface Builder

在 storyboard 中创建一个父子关系的容器,非常容易,拖一个 container view object 到 VC 上,里面可以嵌入任意的 child VC,你可以随意更改 container view 的尺寸和位置

Implementing a Custom Container View Controller

为了实现一个 容器类 VC,你必须建立这种父子关系,即你的 fVC 和 其他 cVC 的父子关系,即让 UIKit 知晓你的 fVC 管理着 cVC 的尺寸和大小,你可以通过 IB 或代码方式实现这种关系,当使用代码方式创建父子关系时,你可以明确的添加或移除 子VC 作为 View Controller 设置的一部分。

Adding a Child View Controller to Your Content

通过代码方式将 child view controller 纳入你的 容器 VC,一般通过以下步骤:

  • 在容器 VC 上调用 addChildViewController:
  • 将子 VC 的根视图添加到容器 VC 的 view 层级结构上,这步别忘了设置子 view 的 frame 的位置和尺寸
  • 为 child's root view 添加约束
  • 在子 VC 上调用 didMoveToParentViewController:
- (void) displayContentController: (UIViewController*) content {
   [self addChildViewController:content];
   content.view.frame = [self frameForContentController];
   [self.view addSubview:self.currentClientView];
   [content didMoveToParentViewController:self];
}

注意在 子VC 上调用了 didMoveToParentViewController 方法,这是因为调用 addChildViewController: 时会触发子 VC 的 willMoveToParentViewController: 。所以之后你必须要在 子VC 上调用 didMoveToParentViewController:

当使用 Auto Layout 时,设置在 容器 view子 view 上的约束只会影响 子 VC根视图,并不会影响 子 VC 上的 view 层级

Removing a Child View Controller

移除 child view controller 也要遵循下面的步骤:

  • 调用子 VCwillMoveToParentViewController:
  • 移除 子 VC 根视图上的任何约束
  • 从容器 View 层级结构中移除子视图
  • 子VC 上调用 removeFromParentViewController 方法

移除 子 VC 会彻底打破这种父子关系,因此只有在不需要时才会移除。比如 navigation controller 只会在 pop VC 的时候才会移除,而 push 操作的时候并不会

- (void) hideContentController: (UIViewController*) content {
   [content willMoveToParentViewController:nil];
   [content.view removeFromSuperview];
   [content removeFromParentViewController];
}

Transitioning Between Child View Controllers

容器内的 子VC 可以采取动画的方式相互替换,在动画的过程中就是让旧 VC 移出屏幕,让新 VC 移入屏幕。在之后的 completion block 中完成最终的移除。

- (void)cycleFromViewController: (UIViewController*) oldVC
               toViewController: (UIViewController*) newVC {
   // Prepare the two view controllers for the change.
   [oldVC willMoveToParentViewController:nil];
   [self addChildViewController:newVC];

   // Get the start frame of the new view controller and the end frame
   // for the old view controller. Both rectangles are offscreen.
   newVC.view.frame = [self newViewStartFrame];
   CGRect endFrame = [self oldViewEndFrame];

   // Queue up the transition animation.
   [self transitionFromViewController: oldVC toViewController: newVC
        duration: 0.25 options:0
        animations:^{
            // Animate the views to their final positions.
            newVC.view.frame = oldVC.view.frame;
            oldVC.view.frame = endFrame;
        }
        completion:^(BOOL finished) {
           // Remove the old view controller and send the final
           // notification to the new view controller.
           [oldVC removeFromParentViewController];
           [newVC didMoveToParentViewController:self];
        }];
}

Managing Appearance Updates for Children

子 VC 添加到 容器 VC 中,容器 VC 会自动转发 外观类的信息子 VC,但是如果你想要控制这一过程,可以覆盖 shouldAutomaticallyForwardAppearanceMethods 方法,让其返回 NO,在外观改变时,手动调用 子 VCbeginAppearanceTransition:animated:endAppearanceTransition 来控制 子 VC 的外观变化

-(void) viewWillAppear:(BOOL)animated {
    [self.child beginAppearanceTransition: YES animated: animated];
}

-(void) viewDidAppear:(BOOL)animated {
    [self.child endAppearanceTransition];
}

-(void) viewWillDisappear:(BOOL)animated {
    [self.child beginAppearanceTransition: NO animated: animated];
}

-(void) viewDidDisappear:(BOOL)animated {
    [self.child endAppearanceTransition];
}

Suggestions for Building a Container View Controller

实现一个容器其实要考虑的事情很多,有如下建议:

  • Access only the root view of a child view controller. 父容器仅仅能访问 子 VC 的根视图,即容器不应该访问 child 的其他子视图
  • Child view controllers should have minimal knowledge of their container. 子 VC 要对自身的父容器知道的尽可能的少
  • Design your container using regular views first. 设计容器 VC 时,先用基本的视图来试验下尺寸,位置,约束什么的,不着急拿 child View 来做

Delegating Control to a Child View Controller

容器 VC 可以将自身外观委托给 child VC 来决定,一般有如下方式:

  • 子 VC 来决定 status bar style,你需要在 容器 VC 中实现 childViewControllerForStatusBarStylechildViewControllerForStatusBarHidden
  • 子 VC 决定合适的尺寸,容器VC 可以根据 子 VC 的 preferredContentSize 属性来设置灵活的 layout

-EOF-

如果感觉此文对你有帮助,请随意打赏支持作者 😘

chengway

认清生活真相之后依然热爱它!

Subscribe to Talk is cheap, Show me the world!

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!