记录iOS切换页面navigationBar出现闪烁

2020-08-06  本文已影响0人  東玖零

前提:
大家都熟知iOS开发中一个页面开发需要分导航条视图(self.navigationController.navigationBar)和正文视图(self.view)。

场景:
有两个页面A和B,从Apush到B而且B页面设计是整体。

比如A是导航条非透明是正文视图从导航条底部开始展示的红色,B是全屏是蓝色,当我们整屏是同一个色调时,我们有三种选择。

  1. 隐藏系统导航条,让正文视图铺满屏幕;
-(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];
}
  1. 让系统导航条透明让视图从屏幕(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];
}
  1. 按导航条视图和正文视图做一下切割,导航条上设置相应背景图,看起来是一个整体。
-(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的颜色。

至此我们找到了闪烁的原因!

解决方法有一条是我们自定义转场动画,还有其他骚操作还看各位大神了。

如何自定义转场动画还需要各位大神查找相关资料,凌晨两点了,睡觉~

上一篇 下一篇

猜你喜欢

热点阅读