iOS 导航栏透明

在最近一个项目中碰到这样一个场景,在被push进来的一个页面设置导航栏透明,且要求控制对tableview组的头视图进行悬停显示,nav随着tableview偏移量改变透明度,当然这样的需求确实不是什么难事,但是如果当前页面继续push一个不需要此类效果的页面,当在返回当前页面的时候就会出现一个坑,nav的展示很突兀,下面是直接上解决方法...ps:假设A页面为需要设置透明,B页面被Apush且不需要设置透明

A.m

首先在需要设置导航栏透明的页面的viewDidload中写上

self.title = @"Title";
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
    self.navigationController.navigationBar.shadowImage = [UIImage new];
    self.barImageView = self.navigationController.navigationBar.subviews.firstObject;
    self.barImageView.alpha = 0;
    //设置状态栏
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
    //设置标题颜色
    self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor clearColor]};
   

在scrollViewDidScroll代理方法中

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
 
    CGFloat offset = scrollView.contentOffset.y;
    //根据自己需要设置(136)的大小
    CGFloat alpha = offset / 136;
    _barImageView.alpha = alpha;
    //记录下当前的透明度,在返回当前页面时需要
    _alpha = alpha;
    [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithFloat:alpha] forKey:@"_alpha"];
    //设置标题的透明度
    self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor colorWithWhite:0 alpha:alpha]};
}

当前页的viewWillAppear, viewDidAppear, viewWillDisappear

-(void)viewWillAppear:(BOOL)animated
{
    
    [super viewWillAppear:animated];
    self.table.delegate = self;

   BOOL isGesturePop = [[[NSUserDefaults standardUserDefaults] objectForKey:@"isGesturePop"] boolValue];
    self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor colorWithWhite:0 alpha:_alpha]};
    if (!isGesturePop) {
        [UIView animateWithDuration:0.25 animations:^{
            _barImageView.alpha = _alpha;
            self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor colorWithWhite:0 alpha:_alpha]};
        }];
    }
}

-(void)viewDidAppear:(BOOL)animated {
    //BOOL isGesturePop = [[[NSUserDefaults standardUserDefaults] objectForKey:@"isGesturePop"] boolValue];
//    if (!isGesturePop) {
   //     _barImageView.alpha = _alpha;
      //  self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor colorWithWhite:0 alpha:_alpha]};
    //}
    [super viewDidAppear:animated];
}

-(void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    self.table.delegate = nil;
    self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor blackColor]};
    
    _barImageView.alpha = 1;
    [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:@"isGesturePop"];
}

那么在我们需要push的下一个页面需要什么操作呢,我们需要在这个页面显示正常的nav并且禁掉系统的手势pop,自己写一个pop手势,以方便我们拿到pop滑动时的偏移量,在做的时候使用了两个类,在最后会有源码贴出

B.m 须遵守UIGestureRecognizerDelegate,并导入NavigationInteractiveTransition.h

全局变量

@property (nonatomic, strong) NavigationInteractiveTransition *navT;

viewDidLoad

self.navigationController.interactivePopGestureRecognizer.enabled = NO;
    
    UIGestureRecognizer *gesture = self.navigationController.interactivePopGestureRecognizer;
    gesture.enabled = NO;
    UIView *gestureView = gesture.view;
    
    UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] init];
    popRecognizer.delegate = self;
    popRecognizer.maximumNumberOfTouches = 1;
    [gestureView addGestureRecognizer:popRecognizer];
    
    _navT = [[NavigationInteractiveTransition alloc] initWithViewController:self.navigationController];
    [popRecognizer addTarget:_navT action:@selector(handleControllerPop:)];

UIGestureRecognizerDelegate 代理方法gestureRecognizerShouldBegin

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    //记录当前是是否是通过手势滑动回去
    [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:@"isGesturePop"];
    /**
     *  这里有两个条件不允许手势执行,1、当前控制器为根控制器;2、如果这个push、pop动画正在执行(私有属性)
     */
    return self.navigationController.viewControllers.count != 1 && ![[self.navigationController valueForKey:@"_isTransitioning"] boolValue];
}

需要依赖的两个类源码

NavigationInteractiveTransition.h

#import <UIKit/UIKit.h>

@class UIViewController, UIPercentDrivenInteractiveTransition;
@interface NavigationInteractiveTransition : NSObject <UINavigationControllerDelegate>
- (instancetype)initWithViewController:(UIViewController *)vc;
- (void)handleControllerPop:(UIPanGestureRecognizer *)recognizer;
- (UIPercentDrivenInteractiveTransition *)interactivePopTransition;
@end

NavigationInteractiveTransition.m

#import "NavigationInteractiveTransition.h"
#import "PopAnimation.h"

@interface NavigationInteractiveTransition ()
@property (nonatomic, weak) UINavigationController *vc;
@property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactivePopTransition;
@property(nonatomic, strong) UIImageView *barImageView;
@end

@implementation NavigationInteractiveTransition

- (instancetype)initWithViewController:(UIViewController *)vc
{
    self = [super init];
    if (self) {
        self.vc = (UINavigationController *)vc;
        self.vc.delegate = self;
    }
    return self;
}

/**
 *  我们把用户的每次Pan手势操作作为一次pop动画的执行
 */
- (void)handleControllerPop:(UIPanGestureRecognizer *)recognizer {
    /**
     *  interactivePopTransition就是我们说的方法2返回的对象,我们需要更新它的进度来控制Pop动画的流程,我们用手指在视图中的位置与视图宽度比例作为它的进度。
     */
    CGFloat progress = [recognizer translationInView:recognizer.view].x / recognizer.view.bounds.size.width;
    [self.vc.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
    self.vc.navigationBar.shadowImage = [UIImage new];
    self.barImageView = self.vc.navigationBar.subviews.firstObject;
    
    CGFloat alpha = [[[NSUserDefaults standardUserDefaults] objectForKey:@"_alpha"] floatValue];
    self.barImageView.alpha = 1 - progress > alpha ? alpha : 1 - progress;
//    NSLog(@"===progress==%.2f",progress);
    /**
     *  稳定进度区间,让它在0.0(未完成)~1.0(已完成)之间
     */
    progress = MIN(1.0, MAX(0.0, progress));
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        /**
         *  手势开始,新建一个监控对象
         */
        self.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
        /**
         *  告诉控制器开始执行pop的动画
         */
        [self.vc popViewControllerAnimated:YES];
    }
    else if (recognizer.state == UIGestureRecognizerStateChanged) {
        
        /**
         *  更新手势的完成进度
         */
        [self.interactivePopTransition updateInteractiveTransition:progress];
    }
    else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
        
        /**
         *  手势结束时如果进度大于一半,那么就完成pop操作,否则重新来过。
         */
        if (progress > 0.5) {
            [self.interactivePopTransition finishInteractiveTransition];
            self.barImageView.alpha = 0;;
        }
        else {
            [self.interactivePopTransition cancelInteractiveTransition];
        }

        self.interactivePopTransition = nil;
    }
    
}

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                  animationControllerForOperation:(UINavigationControllerOperation)operation
                                               fromViewController:(UIViewController *)fromVC
                                                 toViewController:(UIViewController *)toVC {
    /**
     *  方法1中判断如果当前执行的是Pop操作,就返回我们自定义的Pop动画对象。
     */
    if (operation == UINavigationControllerOperationPop)
        return [[PopAnimation alloc] init];

    return nil;
}

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                         interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {

    /**
     *  方法2会传给你当前的动画对象animationController,判断如果是我们自定义的Pop动画对象,那么就返回interactivePopTransition来监控动画完成度。
     */
    if ([animationController isKindOfClass:[PopAnimation class]])
        return self.interactivePopTransition;

    return nil;
}

@end

PopAnimation.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface PopAnimation : NSObject <UIViewControllerAnimatedTransitioning>

@end

PopAnimation.m

#import "PopAnimation.h"

@interface PopAnimation ()
@property (nonatomic, strong) id <UIViewControllerContextTransitioning> transitionContext;
@end

@implementation PopAnimation

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
    //这个方法返回动画执行的时间
    return 0.25;
}

/**
 *  transitionContext你可以看作是一个工具,用来获取一系列动画执行相关的对象,并且通知系统动画是否完成等功能。
 */
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
    /**
     *  获取动画来自的那个控制器
     */
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    /**
     *  获取转场到的那个控制器
     */
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
    /**
     *  转场动画是两个控制器视图时间的动画,需要一个containerView来作为一个“舞台”,让动画执行。
     */
    UIView *containerView = [transitionContext containerView];
    [containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
    
    NSTimeInterval duration = [self transitionDuration:transitionContext];

    /**
     *  执行动画,我们让fromVC的视图移动到屏幕最右侧
     */
    [UIView animateWithDuration:duration animations:^{
        fromViewController.view.transform = CGAffineTransformMakeTranslation([UIScreen mainScreen].bounds.size.width, 0);
    }completion:^(BOOL finished) {
        /**
         *  当你的动画执行完成,这个方法必须要调用,否则系统会认为你的其余任何操作都在动画执行过程中。
         */
        [transitionContext completeTransition:!transitionContext.transitionWasCancelled];
    }];

}

- (void)animationDidStop:(CATransition *)anim finished:(BOOL)flag {
    [_transitionContext completeTransition:!_transitionContext.transitionWasCancelled];
}
@end

ps:如果是自定义view设置nav或者是直接隐藏nav可以参考我的另一篇简书http://www.jianshu.com/p/b46166b05f02
备注:还有些许不足请各位见谅指正

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • 在写透明导航栏的时候,如果没有侧滑手势pop控制器倒是一件简单的事。如我之前的项目一样,直接设置就行了,也不应考虑...
    损失了成吨智商的小海Jy阅读 4,279评论 0 6
  • 最近碰到项目需求是一个导航栏多种样式的处理 而且有些页面还需要渐变效果 没办法看了很多demo 还是没有符合需求的...
    Alife丶阅读 1,340评论 1 4
  • 开发过程中,会遇到导航栏透明问题。如下图的需求: 要实现这个效果要注意到的点: 1、系统有提供隐藏导航栏的方法 o...
    槑槑鹤阅读 1,233评论 1 8
  • 像这样的效果,navigationController.navigationBar变为透明,同时又不影响返回等按钮...
    黑色桃芯阅读 427评论 0 3
  • 功能需求:根新浪微博个人主页类似,下拉拉伸放大图片下拉刷新(前面文章已解决),向上滑动的时候,导航栏的透明度逐渐增...
    啓蘊阅读 679评论 1 2