前提:
大家都熟知iOS开发中一个页面开发需要分导航条视图(self.navigationController.navigationBar)和正文视图(self.view)。
场景:
有两个页面A和B,从Apush到B而且B页面设计是整体。
比如A是导航条非透明是正文视图从导航条底部开始展示的红色,B是全屏是蓝色,当我们整屏是同一个色调时,我们有三种选择。
- 隐藏系统导航条,让正文视图铺满屏幕;
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
- 让系统导航条透明让视图从屏幕(0,0)位置开始显示铺满屏幕;
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self setEdgesForExtendedLayout:UIRectEdgeAll];
[self.navigationController.navigationBar setTranslucent:YES];
[self.navigationController.navigationBar setShadowImage:[UIColor clearColor].image];
[self.navigationController.navigationBar setBackgroundImage:[UIColor clearColor].image forBarMetrics:UIBarMetricsDefault];
}
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigationController.navigationBar setTranslucent:NO];
[self.navigationController.navigationBar setShadowImage:nil];
[self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
}
- 按导航条视图和正文视图做一下切割,导航条上设置相应背景图,看起来是一个整体。
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self setEdgesForExtendedLayout:UIRectEdgeNone];
[self.navigationController.navigationBar setTranslucent:NO];
[self.navigationController.navigationBar setShadowImage:[UIColor clearColor].image];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"导航背景"] forBarMetrics:UIBarMetricsDefault];
}
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigationController.navigationBar setShadowImage:nil];
[self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
}
第一种选择,隐藏系统导航条,如果有导航需求,那么我们就需要自定导航条。
第二种选择,看起来很完美,页面切换做动画时导航条会闪烁。
第三种选择,就是整体会被割裂,如果是页面是列表下拉就出现断层。
无论是哪种选择都可以满足一定的需求开发,根据需求而定选择哪一种。
今天我们就来简单的分析一下第二种会闪烁的问题,这就不得不去了解iOS转场动画了。
#import "CustomAdongAnimate.h"
#import <UIKit/UIKit.h>
@interface CustomAdongAnimate () <UIViewControllerAnimatedTransitioning>
@end
@implementation CustomAdongAnimate
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext {
return 3;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
if (!self.isPop) {
[self push:transitionContext];
} else {
[self pop:transitionContext];
}
}
- (void)push:(id <UIViewControllerContextTransitioning>)transitionContext {
UIView *containerView = [transitionContext containerView];
for (UIView * v in containerView.subviews) {
NSLog(@"sub---%@",v);
}
NSLog(@"000---%@",containerView);
NSLog(@"111---%@",containerView.superview);
NSLog(@"222---%@",containerView.superview.superview);
NSLog(@"333---%@",containerView.superview.superview.superview);
NSLog(@"444---%@",containerView.superview.superview.superview.superview);
NSLog(@"555---%@",containerView.superview.superview.superview.superview.superview);
UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
toView.frame = CGRectMake(toView.frame.size.width, 0, toView.frame.size.width, toView.frame.size.height);
[containerView addSubview:fromView];
[containerView addSubview:toView];
NSTimeInterval interval = [self transitionDuration:transitionContext];
[UIView animateWithDuration:interval animations:^{
toView.frame = CGRectMake(0 , 0, toView.frame.size.width, toView.frame.size.height);
fromView.frame = CGRectMake(-100, 0, toView.frame.size.width, toView.frame.size.height);
} completion:^(BOOL finished) {
BOOL cancel = [transitionContext transitionWasCancelled];
[transitionContext completeTransition:!cancel];
if (!cancel) {
[fromView removeFromSuperview];
}
}];
}
- (void)pop:(id <UIViewControllerContextTransitioning>)transitionContext {
//取出转场前后视图控制器上的视图view
UIView * toView = [transitionContext viewForKey:UITransitionContextToViewKey];
UIView * fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
UIView *containerView = [transitionContext containerView];
//加入动画视图
[containerView addSubview:toView];
[containerView addSubview:fromView];
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
fromView.frame = CGRectMake(fromView.frame.size.width, 0, fromView.frame.size.width, fromView.frame.size.height);
}
completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
[fromView removeFromSuperview];
}];
}
@end
上面就是自己定义转场动画最核心的代码,写得比较简单,凑合看。
push做动画的时候我有输出如下:
subs---<UIView: 0x7fca2fc15b10; frame = (0 0; 375 667);>
0000---<UIViewControllerWrapperView: 0x7fca2ff2eb90; frame = (0 0; 375 667);>
sup1---<UINavigationTransitionView: 0x7fca2fc05d00; frame = (0 0; 375 667);>
sup2---<UILayoutContainerView: 0x7fca2fe13420; frame = (0 0; 375 667);>
sup3---<UIDropShadowView: 0x7fca2ff0fd10; frame = (0 0; 375 667);>
sup4---<UITransitionView: 0x7fca2ff0f730; frame = (0 0; 375 667);>
sup5---<UIWindow: 0x7fca2fe04480; frame = (0 0; 375 667);>
从上面代码可以看出当转场是其实是 containerView 上的 toView和fromView在做动画。
当我们不去添加fromView到containerView还是能看到fromView,因为containerView的子视图就是fromView。
当我们containerView上的子视图清空发现他是整个屏幕都黑色了,
经测试,其实他也是透明的,通过层级可以看出最后一层是UIWindow,当我们把UIWindow设置了红色,整个屏幕也都是红色。
经测试当使用这个转场动画时是不会出现闪烁,那么为什么系统转场动画会闪烁呢?
从代码上我们设置toView和fromView的Y都是从0开始的,出现了闪烁就是 toView和fromView做动画的时候不是从0开始,而是从导航条下方开始,导航条又是透明的。如果不做过多的颜色设置,闪烁的颜色一定是UIWindow的颜色。
至此我们找到了闪烁的原因!
解决方法有一条是我们自定义转场动画,还有其他骚操作还看各位大神了。
如何自定义转场动画还需要各位大神查找相关资料,凌晨两点了,睡觉~
网友评论