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

在最近一个项目中碰到这样一个场景,在被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

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

(0)

相关推荐

  • IOS实现自定义透明背景的tabbar

    话不多说,直接看示例代码 ``` // UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, kScreenW, tabBarHeight + 5)]; // [imageView setImage:[self createImageWithColor:[UIColor clearColor]]]; // [imageView setContentMode:UIViewContentModeScal

  • iOS中设置父视图透明但内容不透明的方法

    前言 本文就来给大家讲解一下在iOS中如何将父试图设置为透明而其里面的内容不透明的方法,分享出来供大家参考学习,下面来一起看看详细的介绍. 方法如下: 错误的做法 self.view.backgroundColor = [UIColor clearColor]; self.view.alpha = 0.5; 这样写虽然可以达到透明的效果,往往也会造成添加改self.view视图上面的所有子视图的会产生透明,然而这往往是我们不需要的. 正确的做法 self.view.backgroundColor

  • iOS轻松实现导航栏透明渐变

    首先我们来看下效果 一开始当我们什么只设置了一张图片作为它的头部视图的时候,它是这样的 1.首当其冲的,我们先得把导航栏弄透明 那么我们首先得知道,设置navigationBar的BackgroundColor为Clear是没用的,你可以试着设置它的clear,但是没用,原因一会儿我们就知道了. 而对于把导航栏设置为透明,网上大多数的方法是: [self.navigationController.navigationBar setBackgroundImage:[UIImage new] for

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

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

  • element-ui 实现响应式导航栏的示例代码

    开始之前 按照计划,前端使用Vue.js+Element UI,但在设计导航栏时,发现element没有提供传统意义上的页面顶部导航栏组件,只有一个可以用在很多需要选择tab场景的导航菜单,便决定在其基础上改造,由于我认为实现移动端良好的体验是必须的,所以便萌生了给其增加响应式功能的想法. 需求分析与拆解 假设我们的导航栏有logo和四个el-menu-item. 给window绑定监听事件,当宽度小于a时,四个链接全部放入右侧el-submenu的子菜单: 当宽度大于a时,右侧el-subme

  • react+zarm实现底部导航栏的示例代码

    目录 需要实现的效果 实现过程 1.使用 prop-types 库进行类型检查 2.使用 useNavigate 3.编写标签栏组件 4.使用标签栏组件 5.添加对应的页面路由 6.效果 参考资料 需要实现的效果 需要实现下面栏目固定,并且点击时切换到不同页面路由 实现过程 1.使用 prop-types 库进行类型检查 注意:自 React v15.5 起,React.PropTypes 已移入另一个包中.请使用 prop-types 库 代替. PropTypes 提供了使用不同验证器的例子

  • iOS 封装导航栏及返回,获取控件所在控制器的实例

    当一个项目发现每个返回的按钮都是一样的,并且标题的字体也不是系统的字体,如果每个页面都去设置返回按钮,重新设置标题字体,这样代码看着繁杂,而且会浪费很多时间,这时候就有必要封装一下了... 首先返回按钮,需要在当前页面pop 到上一个页面的话,有两种方式:一 写一个点击代理,在用到的页面实现它,二 就是获取button所在的当前控制器,然后pop出去. 但是第一个方法,还需要到用到的页面去实现代理,也比较麻烦,那就来说第二种 首先获取当前控制器的方法: UINavigationControlle

  • iOS 设置导航条透明效果的实例代码

    APP中很多界面都是这样的.从有不透明到透明,透明到不透明 以下代码即可实现该功能 //设置导航栏透明 func setNavigationIsTranslucent(isTranslucent:Bool) { if isTranslucent == true { self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default) self.navigationController?.navi

  • 微信小程序MUI导航栏透明渐变功能示例(通过改变rgba的a值实现)

    本文实例讲述了微信小程序MUI导航栏透明渐变功能.分享给大家供大家参考,具体如下: 导航栏透明渐变效果 实现原理 1. 给page-group设置的背景颜色采用rgba; 2. 通过改变rgba其中a的值来实现透明渐变. WXML <view style="height:100%;position:fixed;width:100%;"> <scroll-view scroll-y="false" bindscroll="scroll&qu

  • 微信小程序MUI导航栏透明渐变功能示例(通过改变opacity实现)

    本文实例讲述了微信小程序MUI导航栏透明渐变功能.分享给大家供大家参考,具体如下: 导航栏透明渐变效果 实现原理 1. 利用position:absolute在导航下定位一个view作为背景渐变使用; 2. 通过改变改view的opacity来实现透明渐变. WXML <!--pages/scroll/scroll.wxml--> <view style="height:100%;position:fixed;width:100%;"> <scroll-v

  • iOS中导航栏的基本使用汇总

    一.设置导航栏样式 设置导航栏的样式可分为全局设置与局部设置: 1.全局设置 全局设置一般的都是在AppDelegate中设置,这样整个app都会生效,相关的代码与效果图如下: //1.设置导航栏背景颜色 [[UINavigationBar appearance] setBarTintColor:[UIColor orangeColor]]; //2.设置导航栏背景图片 [[UINavigationBar appearance] setBackgroundImage:[UIImage image

  • IOS 改变导航栏返回按钮的标题实例详解

    IOS 改变导航栏返回按钮的标题实例详解 前言: 下午又找到了一个新的方法 这个方法不错 暂时没有发现异常的地方. 新写的App中需要使用UINavigationController对各个页面进行导航,但由于第一级页面的title较长,在进入第二级页面后返回按钮leftButtonItem的title就会变得很长,对NavigationBar空间占用很大,而且不美观,于是使用代码对leftButtonItem的title文本进行修改,无论是设置self.navigationItem.leftBa

  • 原生JS实现 MUI导航栏透明渐变效果

    mui内置有H5版本的透明渐变导航控件,教程参考mui官网:透明渐变导航是一种解决滚动条通顶的变通方案,相比双webview,具有更高的性能和更好的动画效果: 下面通过本文给大家分享基于原生JS实现 MUI导航栏透明渐变效果,具体内容详情如下所示: 首先声明:由于backgroundColor的值采用的是RGBA,IE8及以下不支持,所以此效果不支持IE8及以下的浏览器 css代码 body,p,h1{margin: 0;} .module-layer{ width: 100%; positio

随机推荐