iOS UI相关iOS Developer闻道丶iOS(尝鲜版)

源码分析--KMNavigationBarTransition

2017-03-07  本文已影响1046人  奇董

最近项目迭代的速度比较慢,准备安心学习一下一些优秀库的源码。记录下来与小伙伴们一同进步。

问题

NavigationBar 是目前市面app几乎都用到的一种控件,很多情况下我们NavigationController栈里面的ViewController对应的NavigationBar样式都是有区别的。然而NavigationBar是由NavigationController统一管理的。
🌰:
A页面 -》 B页面
你在A页面中修改了Bar的样式,随之B页面也会修改。只能A修改了A的样式,B在修改回来。这样咋看是没有问题的,但涉及到右滑返回的时候,就会出现各种问题。

处理

我一开始是在NavigationController的代理中去选择页面对应的样式。但这样,依旧无法避免右滑返回的尴尬。

KMNavigationBarTransition 是新美大的童鞋开源的三方库。我们来分析一下 如何顺滑的处理这方面的动画问题。

先文字说明一下:

隐藏原Bar: 其实不是隐藏Bar 而是隐藏bar上的_backgroundView(我们设置的大部分效果都在这个view上显示)只要我们隐藏了这个view,Bar就变成了一个透明没有效果的Bar。这样相对于完全自定义Bar,可以保留了item切换的动画效果

就是在pop push的时候 隐藏原生的bar(隐藏_backgroundView),在2个VC的view上分别加上替身bar 。

            页面A     --》   页面B
                    push操作
---------------------------------
begin A+替身Bar       原Bar隐藏     B+替身Bar  
---------------------------------
end                  B-替身Bar 原Bar 显示


             页面A     《-   页面B
                    pop操作
---------------------------------
begin                       B+替身Bar  原生Bar隐藏
---------------------------------
end A-替身Bar 原生Bar显示
```

看代码分析
#####push
1 push 开始 这时候页面A 就拥有一个和原本Bar相同的替身Bar
```
- (void)km_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    // 1 获取页面A 的实例
    UIViewController *disappearingViewController = self.viewControllers.lastObject;
    if (!disappearingViewController) {
        return [self km_pushViewController:viewController animated:animated];
    }
    // 2 判断页面A 上不存在替身Bar
    if (!self.km_transitionContextToViewController || !disappearingViewController.km_transitionNavigationBar) {
        // 3 页面 A.view add 一个和原Bar相同属性的Bar
    [disappearingViewController km_addTransitionNavigationBarIfNeeded];
    }

    if (animated) {
        self.km_transitionContextToViewController = viewController;
        if (disappearingViewController.km_transitionNavigationBar) {
            // 4 隐藏原生Bar
            disappearingViewController.km_prefersNavigationBarBackgroundViewHidden = YES;
        }
    }
    return [self km_pushViewController:viewController animated:animated];
}
```
2 Push 到 页面B 加载过程中 这时候页面B 也拥有了替身Bar
```
- (void)km_viewWillLayoutSubviews {
    id<UIViewControllerTransitionCoordinator> tc = self.transitionCoordinator;
    //1. 获取push 过程中的页面A 和 页面B 实例
    UIViewController *fromViewController = [tc viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toViewController = [tc viewControllerForKey:UITransitionContextToViewControllerKey];
    //2 判断 当前页面加载是否是页面B
    if ([self isEqual:self.navigationController.viewControllers.lastObject] && [toViewController isEqual:self] && self.navigationController.km_transitionContextToViewController) {
        if (self.navigationController.navigationBar.translucent) {
            [tc containerView].backgroundColor = [self.navigationController km_containerViewBackgroundColor];
        }
        fromViewController.view.clipsToBounds = NO;
        toViewController.view.clipsToBounds = NO;
        //3 判断页面B 上是否有替身Bar 没有add 替身Bar
        if (!self.km_transitionNavigationBar) {
            [self km_addTransitionNavigationBarIfNeeded];
            //4 隐藏 原生Bar
            self.km_prefersNavigationBarBackgroundViewHidden = YES;
        }
        [self km_resizeTransitionNavigationBarFrame];
    }
    if (self.km_transitionNavigationBar) {
        [self.view bringSubviewToFront:self.km_transitionNavigationBar];
    }
    [self km_viewWillLayoutSubviews];
}
```
3 push 完成 页面B 完全加载。这时候B 的替身Bar,任务完成。
```
- (void)km_viewDidAppear:(BOOL)animated {
    //1 将 替身Bar 的属性 还给 原生Bar
    if (self.km_transitionNavigationBar) {
        self.navigationController.navigationBar.barTintColor = self.km_transitionNavigationBar.barTintColor;
        [self.navigationController.navigationBar setBackgroundImage:[self.km_transitionNavigationBar backgroundImageForBarMetrics:UIBarMetricsDefault] forBarMetrics:UIBarMetricsDefault];
        [self.navigationController.navigationBar setShadowImage:self.km_transitionNavigationBar.shadowImage];
        
        UIViewController *transitionViewController = self.navigationController.km_transitionContextToViewController;
        if (!transitionViewController || [transitionViewController isEqual:self]) {
            [self.km_transitionNavigationBar removeFromSuperview];
            self.km_transitionNavigationBar = nil;
            self.navigationController.km_transitionContextToViewController = nil;
        }
    }
    //2 显示 原生Bar
    self.km_prefersNavigationBarBackgroundViewHidden = NO;
    [self km_viewDidAppear:animated];
}
```
#####pop
pop 才是关键 因为pop是可以 右滑返回的
1 pop 开始 加上替身Bar 隐藏原生Bar
```
- (UIViewController *)km_popViewControllerAnimated:(BOOL)animated {
    if (self.viewControllers.count < 2) {
        return [self km_popViewControllerAnimated:animated];
    }
    UIViewController *disappearingViewController = self.viewControllers.lastObject;
    //1 页面B 重新加上 替身Bar
    [disappearingViewController km_addTransitionNavigationBarIfNeeded];
    UIViewController *appearingViewController = self.viewControllers[self.viewControllers.count - 2];
    if (appearingViewController.km_transitionNavigationBar) {
        UINavigationBar *appearingNavigationBar = appearingViewController.km_transitionNavigationBar;
        self.navigationBar.barTintColor = appearingNavigationBar.barTintColor;
        [self.navigationBar setBackgroundImage:[appearingNavigationBar backgroundImageForBarMetrics:UIBarMetricsDefault] forBarMetrics:UIBarMetricsDefault];
        self.navigationBar.shadowImage = appearingNavigationBar.shadowImage;
    }
    if (animated) {
        // 原生Bar 隐藏
        disappearingViewController.km_prefersNavigationBarBackgroundViewHidden = YES;
    }
    return [self km_popViewControllerAnimated:animated];
}
``` 
2 因为 push 操作 已经给页面A加上了替身Bar
直接pop结束, 去掉A 的替身Bar,显示原生Bar
```
- (void)km_viewDidAppear:(BOOL)animated {
    //1 将 替身Bar 的属性 还给 原生Bar
    if (self.km_transitionNavigationBar) {
        self.navigationController.navigationBar.barTintColor = self.km_transitionNavigationBar.barTintColor;
        [self.navigationController.navigationBar setBackgroundImage:[self.km_transitionNavigationBar backgroundImageForBarMetrics:UIBarMetricsDefault] forBarMetrics:UIBarMetricsDefault];
        [self.navigationController.navigationBar setShadowImage:self.km_transitionNavigationBar.shadowImage];
        
        UIViewController *transitionViewController = self.navigationController.km_transitionContextToViewController;
        if (!transitionViewController || [transitionViewController isEqual:self]) {
            [self.km_transitionNavigationBar removeFromSuperview];
            self.km_transitionNavigationBar = nil;
            self.navigationController.km_transitionContextToViewController = nil;
        }
    }
    //2 显示 原生Bar
    self.km_prefersNavigationBarBackgroundViewHidden = NO;
    [self km_viewDidAppear:animated];
}
```
效果

![Now1.gif](https://img.haomeiwen.com/i1106106/c5fd7b3f93ee5b9b.gif?imageMogr2/auto-orient/strip)

大家如果想看源码,可以去github上 搜索新美大同学的这个三方库。大家一起学习进步~
上一篇下一篇

猜你喜欢

热点阅读