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, span) 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, span) UIPercentDrivenInteractiveTransition *interactivePopTransition;

@property(nonatomic, span) 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, span) 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

以上是 iOS实现导航栏透明示例代码 的全部内容, 来源链接: utcz.com/z/324953.html

回到顶部