父子控制器
在 iOS 开发中我们经常用到的两大父子控制器分别是:UINavigationController 和 UITabBarController。但是经常也会为了实现一些需求,自己去写一个类似于 UITabBarController 的功能,也就是点击按钮切换控制器,如图:
QQ功能都类似于 UITabBarController,点击切换控制器。只不过将 UITabBarController 底部的按钮,移到顶部,或者其他位置去了。这时候就得自己去实现一个父子控制器。
实现
完成界面如图所示:
父子控制器.gif
首先新建一个项目,创建一个父控制器,然后创建三个子控制器,如图:
目录结构
对父控制器上面的三个菜单按钮分别添加 tag 来进行区分,拖一个点击事件,都跳转到同一个方法。然后在父控制器里面,进行子控制器的添加和切换操作:
@interface ViewController ()
@property (nonatomic, weak) UIViewController *currentVC;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 添加子控制器
[self addChildViewController:[[OneViewController alloc] init]];
[self addChildViewController:[[TowViewController alloc] init]];
[self addChildViewController:[[ThreeViewController alloc] init]];
}
- (IBAction)clickMenu:(UIButton *)btn {
// 取出选中的这个控制器
UIViewController *vc = self.childViewControllers[btn.tag];
// 设置尺寸位置
vc.view.frame = CGRectMake(0, 70, self.view.frame.size.width, self.view.frame.size.height - 50);
// 移除掉当前显示的控制器的view(移除的是view,而不是控制器)
[self.currentVC.view removeFromSuperview];
// 把选中的控制器view显示到界面上
[self.view addSubview:vc.view];
self.currentVC = vc;
}
其中,currentVC 属性用来记录当前正在显示的 view。如果进行切换操作,要把 currentVC 从父类的 view 中移除掉。
不移除的后果是:界面上会显示出所有的 view,只不过你只能看到最上面那个。会增加系统的开销。
整体还是非常简单的,在 UIViewController 里面,有一个数组用来专门存放子控制器,可以方便进行管理。当然也可以自己在父控制器里面建立一个数组来对子控制器进行管理。不过这样会产生一些问题,稍后会说到。
我 Demo 中的例子非常简单。实际开发中,子控制器的 View 可能是 UITableView 或者其他更为复杂的界面布局,这个时候使用父子控制器显得尤为重要。这样子控制器可以对自己的 view 进行管理,不必什么操作都放到父控制器中,也符合高内聚,低耦合
的开发原则。
结论
使用系统带的 childViewControllers 数组有很多好处。
1、当父控制器有一些重大的事件发生,可以通知到自控制器。比如:屏幕旋转等。
2、如果程序是一个基于 UINavigationController 的逻辑,那么子控制器可能会做以下调用 self.navigationController
。如果不把子控制器添加到 childViewControllers 数组中,子控制器拿到的self.navigationController
为空。
结论:不要自己创建数组来管理子控制器,用 UIViewController 自带的 childViewControllers 数组可以避免掉很多不必要的麻烦。
扩展
可以在整体布局中嵌套一个 ScrollView,使子控制器可以进行滑动切换,实现类似于网易新闻的效果。
也可以在切换 view 时加入动画。
网友评论
2:整体布局中嵌套一个 ScrollView,使子控制器可以进行滑动切换。。滑动式切换会触发对应要显示的控制器的生命周期吗?
3:第二种,代码控制平滑滚动时候,中间过度的子控制器会触发生命周期吗?
请问怎么通知? 代理或者通知吗?