前言
最近接触到新公司的老项目改版。自从来了之后一直在忙另一个项目,也没有看老项目的实现逻辑。
看到设计稿的时候,并不是普通的树形标签导航的样子。大致效果如FaceU的主页:
布局类似,但是功能有点不一样:
- 顶部左侧的按钮点击后会出现个人中心页。
- 顶部中间还有个按钮,点击会出现一个业务页
- 顶部左侧的按钮也会出现业务页。
刚看完之后,感觉这种设计真麻烦。最爱UITabBarController+UINavgationController
的CP组合好像失效的。难道只能用present
来实现么。
经同事指导,最后找到Container View Controllers Quickstart,才发现一种新的转场实现方式。下面就动手实践一下。
第一步,创建项目:
创建一个空的demo project
,怎么创建我就不说了。其他任何选项都不用修改,run
下应该有个黑色的空白页面。
打开viewController.m
创建两个UIButton
:
@interface ViewController ()
@property (nonatomic, strong) UIButton *leftBtn;
@property (nonatomic, strong) UIButton *rightBtn;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.leftBtn];
[self.view addSubview:self.rightBtn];
}
#pragma mrk - subviews
// fram随便写的,主要看效果
- (UIButton *)leftBtn {
if (_leftBtn == nil) {
_leftBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_leftBtn.frame = CGRectMake(0, 60, 100, 100);
_leftBtn.backgroundColor = [UIColor blueColor];
[_leftBtn addTarget:self action:@selector(leftAction) forControlEvents:UIControlEventTouchUpInside];
}
return _leftBtn;
}
- (UIButton *)rightBtn {
if (_rightBtn == nil) {
_rightBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_rightBtn.frame = CGRectMake(kScreenWidth - 100, 60, 100, 100);
_rightBtn.backgroundColor = [UIColor blueColor];
[_rightBtn addTarget:self action:@selector(rightAction) forControlEvents:UIControlEventTouchUpInside];
}
return _rightBtn;
}
@end
run
起来,应该可以看到页面变成白色的,并且带有两个蓝色的色块。这两个色块就代表前言中顶部的左右按钮,点击左边的色块会从左边弹出一个控制器,右边的同理。
第二步,实现弹出控制器:
现在我们给左右按钮addTarget
。
- (void)leftAction {
}
- (void)rightAction {
}
并创建一个左侧的控制器TestOneViewController
:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
NSLog(@"----TestOneViewController didload-");
}
- (void)dealloc {
NSLog(@"----TestOneViewController dealloc--");
}
并用NSLog
来监听它的生命周期。
在`viewcontroller.m
中引入,并添加如下属性方法:
// 记录当前是哪个vc
@property (nonatomic, strong) UIViewController *currentVC;
@property (nonatomic, strong) TestOneViewController *leftVC;
// 移除掉不活动的vc
- (void)removeInactiveVC:(UIViewController *)inActiveVC {
if (inActiveVC) {
[inActiveVC willMoveToParentViewController:nil];
[UIView animateWithDuration:0.2 animations:^{
inActiveVC.view.frame = [self dismissToFrame];
} completion:^(BOOL finished) {
[inActiveVC.view removeFromSuperview];
[inActiveVC removeFromParentViewController];
self.currentVC = nil;
}];
}
}
// currentVC的setter
- (void)setCurrentVC:(UIViewController *)currentVC {
if (_currentVC == currentVC) {
return;
}
[self removeInactiveVC:_currentVC];
_currentVC = currentVC;
[self updateActiveViewContrller];
}
// leftAction的实现
- (void)leftAction {
self.currentVC = self.leftVC;
}
// 更新新的vc到当前试图
- (void)updateActiveViewContrller {
if (self.currentVC) {
[self addChildViewController:self.currentVC];
self.currentVC.view.frame = [self dismissToFrame];
[self.view addSubview:self.currentVC.view];
[UIView animateWithDuration:0.2 animations:^{
self.currentVC.view.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
}completion:^(BOOL finished) {
[self.currentVC didMoveToParentViewController:self];
}];
}
}
// leftVC的懒加载
- (TestOneViewController *)leftVC {
if (_leftVC == nil) {
_leftVC = [TestOneViewController new];
}
return _leftVC;
}
运行效果如下(找了个网页压缩了下,还给打上了水印):
相对应的右侧弹出的实现方式一样,只是把Frame
更改下,就可以实现从右侧弹出的效果。具体代码就不贴了。
如果想回到主页,只用写个移除self.currentVC
的方法,调用下就可以了。
- (void)backToMainViewController {
[self removeInactiveVC:self.currentVC];
}
结束,优化。
到这,大致的实现逻辑都已经讲明了。只是代码有点乱。如果要再项目中使用,第一个ViewController
就相当于我们的主页,然后再主页里写这些逻辑就会把主页弄的很臃肿。所以我们其实可可以相UITabbarController
一样,写一个控制器,然后传入需要的UIViewController
数组,就可以实现。这样使用起来也方便,维护也简单。具体封装就不赘述(我也封装的不太好),最终成型的代码,有兴趣的可以看下。有不妥之处请指出。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。