当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS实现导航栏透明示例代码

iOS实现导航栏透明示例代码

2019年07月24日  | 移动技术网移动技术  | 我要评论

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

首先在需要设置导航栏透明的页面的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;

}

-(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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网