美文网首页
记录iOS切换页面navigationBar出现闪烁

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

作者: 東玖零 | 来源:发表于2020-08-06 13:44 被阅读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的颜色。

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

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

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

    相关文章

      网友评论

          本文标题:记录iOS切换页面navigationBar出现闪烁

          本文链接:https://www.haomeiwen.com/subject/pknrrktx.html