Container ViewController自定义转场控制器。

前言

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

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

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

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

现在我们给左右按钮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数组,就可以实现。这样使用起来也方便,维护也简单。具体封装就不赘述(我也封装的不太好),最终成型的代码,有兴趣的可以看下。有不妥之处请指出。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Scott_Mr 个人专栏

ReactiveCocoa(二)

1473
来自专栏移动开发

一个简单的ReactNative demo

本人非前端,请轻喷 ReactNative版本:0.31 github:https://github.com/X-FAN/reactnativelear...

4933
来自专栏哈雷彗星撞地球

iOS Bluetooth 打印小票(二)

在上一篇中介绍了打印小票所需要的命令,这一篇介绍Bluetooth连接蓝牙和打印小票的全过程。

7352
来自专栏技术总结

MJRefresh源码剖析与学习

建议查看原文:https://www.jianshu.com/p/23c876f8ae39(不定时更新)

2454
来自专栏Scott_Mr 个人专栏

自定义转场详解(一)

1522
来自专栏進无尽的文章

实践-小细节Ⅵ

有时候,UITableView 的cell个数很少,可是UITableView的headView又是一个有颜色背景的View,当我们下拉的时候,拉扯出来的区域也...

762
来自专栏LeeCen

WKWebView ajax请求Cookie丢失

发现H5里面 ajax请求失败302,这可能Cookie丢失或Cookie不相同了

5841
来自专栏编程之旅

iOS开发——头像设置及本地沙盒保存,圆形头像显示

现在的APP中,对于头像的设置,我们大多采用圆形头像,并且需要支持从照相机获取或者从相册中选择用户需要的头像,并且保存在本地或者服务器中。

2023
来自专栏哈雷彗星撞地球

RunLoop总结:RunLoop的应用场景(五)阻止App崩溃一次

今天要介绍的RunLoop应用场景感觉很酷炫,我们可能不常用到,但是对于做Crash 收集的 SDK可能会用得比较频繁吧。相比关于RunLoop 可以让应用起死...

1232
来自专栏岑志军的专栏

ReactNative-综合案例(02)

1787

扫码关注云+社区

领取腾讯云代金券