最近项目迭代的速度比较慢,准备安心学习一下一些优秀库的源码。记录下来与小伙伴们一同进步。
问题
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](http://upload-images.jianshu.io/upload_images/1106106-c5fd7b3f93ee5b9b.gif?imageMogr2/auto-orient/strip)
大家如果想看源码,可以去github上 搜索新美大同学的这个三方库。大家一起学习进步~