前言

最近接触到新公司的老项目改版。自从来了之后一直在忙另一个项目,也没有看老项目的实现逻辑。
看到设计稿的时候,并不是普通的树形标签导航的样子。大致效果如FaceU的主页:
clipboard.png

布局类似,但是功能有点不一样:

  1. 顶部左侧的按钮点击后会出现个人中心页。
  2. 顶部中间还有个按钮,点击会出现一个业务页
  3. 顶部左侧的按钮也会出现业务页。

刚看完之后,感觉这种设计真麻烦。最爱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起来,应该可以看到页面变成白色的,并且带有两个蓝色的色块。这两个色块就代表前言中顶部的左右按钮,点击左边的色块会从左边弹出一个控制器,右边的同理。

clipboard.png

第二步,实现弹出控制器:

现在我们给左右按钮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;
}

运行效果如下(找了个网页压缩了下,还给打上了水印):

clipboard.png

相对应的右侧弹出的实现方式一样,只是把Frame更改下,就可以实现从右侧弹出的效果。具体代码就不贴了。

如果想回到主页,只用写个移除self.currentVC的方法,调用下就可以了。

- (void)backToMainViewController {
    [self removeInactiveVC:self.currentVC];
    
}

结束,优化。

到这,大致的实现逻辑都已经讲明了。只是代码有点乱。如果要再项目中使用,第一个ViewController就相当于我们的主页,然后再主页里写这些逻辑就会把主页弄的很臃肿。所以我们其实可可以相UITabbarController一样,写一个控制器,然后传入需要的UIViewController数组,就可以实现。这样使用起来也方便,维护也简单。具体封装就不赘述(我也封装的不太好),最终成型的代码,有兴趣的可以看下。有不妥之处请指出。


CharlieWang
20 声望2 粉丝

Be a cartoon heart