容器视图控制器的创建(WORKING WITH CUSTOM CONTAINER VIEW CONTROLLERS)

来源:互联网 发布:淘宝上手机解锁可靠吗 编辑:程序博客网 时间:2024/05/21 14:43

原文:http://www.thinkandbuild.it/working-with-custom-container-view-controllers/

我们将创建一个点击按钮弹出controller(点击按钮和弹出的次数没有限制)的应用。

下面简要说明如何实现


Container: 它继承自UIViewController,有一个subview属性,subview属性是其他子控制器和点击按钮后生成的新Detail Controller 共同的容器。

Detail: 它是一个简单的UIViewController,它包括一个标签和一个UIGestureRecognizer。在它的视图上滑动,标签的颜色会随机变化。此类的实例将成为容器视图控制器的子控制器。它的视图会赋值给容器的detailView,但是仍有自身管理,并接受手势事件。

源码:https://github.com/ariok/TB_ControllerContainment


添加子控制器

在正式开始之前,感谢FlatUI Kit (https://github.com/Grouper/FlatUIKit) 的作者Jack Flintermann.。FlatUI Kit 真是个特别炫酷的类库。

打开 ContainerViewController.m 找到presentDetailController 函数。这个函数完成新Detail controller加入容器视图控制器的操作。下面我们来看仔细代码


- (void)presentDetailController:(UIViewController*)detailVC{         //0. Remove the current Detail View Controller showed     if(self.currentDetailViewController){        [self removeCurrentDetailViewController];    }         //1. Add the detail controller as child of the container    [self addChildViewController:detailVC];         //2. Define the detail controller's view size    detailVC.view.frame = [self frameForDetailController];         //3. Add the Detail controller's view to the Container's detail view and save a reference to the detail View Controller    [self.detailView addSubview:detailVC.view];    self.currentDetailViewController = detailVC;         //4. Complete the add flow calling the function didMoveToParentViewController    [detailVC didMoveToParentViewController:self]; }


Step 0

此步骤我们一会儿再讨论,但这步的本质就是将当前正在显示的Detail ViewController 从容器中删除。

Step 1

IOS为了自定义容器控制器,加入了很多新的函数。addChildViewController 就是其中一个。就这么简单,我们在容器控制器中加了一个Detail Controller。

Step 2

新创建的Detail Controller的视图将要与容器控制器中预定义好的视图进行连接,所以我们要修改预定义视图的frame。

Step 3

现在,我们将Detail Controller的视图添加到容器的detailView上,并将新建的Detail Controller作为当前的Detail Controller。

Step 4

didMoveToParentViewController也是新加入UIViewController类的一个函数。调用这个函数后,我们发送给Detail Controller 实例一个消息,告诉它,它现在是其他控制器的子控制器。

删除子控制器

现在,我们来看 removeCurrentDetailViewController (与上面函数在同一.m文件中)

 Step 1

我们通过在willMoveToParentViewController 以nil 为参数,给current Detail Controller 发送一条信息,通知它将要从父控制器中移除。

Step 2

current Detail controller的视图从父视图中移除。

Step 3

通过调用标准函数removeFromParentViewController,我们将current Detail Controlle从容器中移除。当这个函数被调用的时候,Detail Controller会自动调用 didMoveToParentViewController,调用时的参数为nil。


结果

第一个Detail Controller在容器的viewDidLoad函数中被创建。initWithString:withColor函数帮我们创建一个DetailViewController实例。我们调用presentDetailController 函数,将刚刚创建的实例作为当前的Detail Controller (current Detail Controller)。

就像之前提到的,按钮在容器控制器的主视图上,当我们按下后,就展示一个新的Detail Controller。我们通过addDetailController来添加按钮事件,代码不多,如下:

- (IBAction)addDetailController:(id)sender {    DetailViewController *detailVC = [[DetailViewController alloc]initWithString:@"This is a new viewController!" withColor:[UIColor asbestosColor]];         /* Mode 1 */    [self presentDetailController:detailVC];         /* Mode 2 */    //[self swapCurrentControllerWith:detailVC];}

添加动画效果

还没有提到动画,下面说说。当我们push一个视图控制器的时候可以加入不同的动画,是个很好的想法。

我们不去分别创建方法来添加或删除Detail Controllers,而是将所有操作都放在一个名为swapCurrentControllerWith的函数,我们将新建的ViewController做为参数传入,下面是完整代码:

- (void)swapCurrentControllerWith:(UIViewController*)viewController{         //1. The current controller is going to be removed    [self.currentDetailViewController willMoveToParentViewController:nil];         //2. The new controller is a new child of the container    [self addChildViewController:viewController];         //3. Setup the new controller's frame depending on the animation you want to obtain    viewController.view.frame = CGRectMake(0, 2000, viewController.view.frame.size.width, viewController.view.frame.size.height);     //The transition automatically removes the old view from the superview and attaches the new controller's view as child of the    //container controller's view         //Save the button position... we'll need it later    CGPoint buttonCenter = self.button.center;         [self transitionFromViewController:self.currentDetailViewController toViewController:viewController                              duration:1.3 options:0                            animations:^{                                                                 //The new controller's view is going to take the position of the current controller's view                                viewController.view.frame = self.currentDetailViewController.view.frame;                                                                 //The current controller's view will be moved outside the window                                self.currentDetailViewController.view.frame = CGRectMake(0,                                                                                         -2000,                                                                                         self.currentDetailViewController.view.frame.size.width,                                                                                         self.currentDetailViewController.view.frame.size.width);                                                                 self.button.center = CGPointMake(buttonCenter.x,1000);                                                              } completion:^(BOOL finished) {                                //Remove the old view controller                                [self.currentDetailViewController removeFromParentViewController];                                                                 //Set the new view controller as current                                self.currentDetailViewController = viewController;                                [self.currentDetailViewController didMoveToParentViewController:self];                                                                 //reset the button position                                [UIView animateWithDuration:0.5 animations:^{                                    self.button.center = buttonCenter;                                }];                                                             }];}  

结论

如果你想添加一个新的子控制器并且删除之前的,按照以下步骤来做,这是每种导航模式里(navigation patterns  比如Navigation 、TabBar)共同的。

1 Current detail controller: [current willMoveToParentViewController:nil]     //当前的控制器
2 Next detail controller: [container addChildViewController:next]  //下一个控制器
2.B Next detail controller: [next willMoveToParentViewController:self] (自动调用2) 
3 Next detail controller: [container.view addSubview:next.view]
4 Current detail controller: [current.view removeFromSuperView]
5 Current detail controller: [current removeFromParentViewController]
6 Current detail controller: [current didMoveToParentViewController:nil] (自动被5调用)
7 Next detail controller: [next didMoveToParentViewController:self]

你可以利用这些新加入的函数来创建自己的导航模式。显然,UINavigationController 和 UITabBarController  就是很好的例子。

他们有不同的逻辑和不同的用处,但是他们有共同的地方,那就是每次只为用户展示一个View Controller。

另外一个关于容器控制器的例子是UISplitViewController,它可以一次展示给用户两个控制器。

简单说,你的自定义容器的本质任务就是管理controller,规定哪个需要显示,哪个不需要,如何让用户在controller之间进行切换。



0 0