iOS实现导航栏透明示例代码
在最近一个项目中碰到这样一个场景,在被push进来的一个页面设置导航栏透明,且要求控制对tableview组的头视图进行悬停显示,nav随着tableview偏移量改变透明度,当然这样的需求确实不是什么难事,但是如果当前页面继续push一个不需要此类效果的页面,当在返回当前页面的时候就会出现一个坑,nav的展示很突兀,下面是直接上解决方法...ps:假设A页面为需要设置透明,B页面被Apush且不需要设置透明
首先在需要设置导航栏透明的页面的viewDidload中写上
self.title=@"Title";
[self.navigationController.navigationBarsetBackgroundImage:[UIImagenew]forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage=[UIImagenew];
self.barImageView=self.navigationController.navigationBar.subviews.firstObject;
self.barImageView.alpha=0;
//设置状态栏
[[UIApplicationsharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent];
//设置标题颜色
self.navigationController.navigationBar.titleTextAttributes=@{NSForegroundColorAttributeName:[UIColorclearColor]};
在scrollViewDidScroll代理方法中
-(void)scrollViewDidScroll:(UIScrollView*)scrollView{
CGFloatoffset=scrollView.contentOffset.y;
//根据自己需要设置(136)的大小
CGFloatalpha=offset/136;
_barImageView.alpha=alpha;
//记录下当前的透明度,在返回当前页面时需要
_alpha=alpha;
[[NSUserDefaultsstandardUserDefaults]setObject:[NSNumbernumberWithFloat:alpha]forKey:@"_alpha"];
//设置标题的透明度
self.navigationController.navigationBar.titleTextAttributes=@{NSForegroundColorAttributeName:[UIColorcolorWithWhite:0alpha:alpha]};
}
当前页的viewWillAppear,viewDidAppear,viewWillDisappear
-(void)viewWillAppear:(BOOL)animated
{
[superviewWillAppear:animated];
self.table.delegate=self;
}
-(void)viewDidAppear:(BOOL)animated{
BOOLisGesturePop=[[[NSUserDefaultsstandardUserDefaults]objectForKey:@"isGesturePop"]boolValue];
if(!isGesturePop){
_barImageView.alpha=_alpha;
self.navigationController.navigationBar.titleTextAttributes=@{NSForegroundColorAttributeName:[UIColorcolorWithWhite:0alpha:_alpha]};
}
[superviewDidAppear:animated];
}
-(void)viewWillDisappear:(BOOL)animated
{
[superviewWillDisappear:animated];
self.table.delegate=nil;
self.navigationController.navigationBar.titleTextAttributes=@{NSForegroundColorAttributeName:[UIColorblackColor]};
_barImageView.alpha=1;
[[NSUserDefaultsstandardUserDefaults]setObject:[NSNumbernumberWithBool: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=[[UIPanGestureRecognizeralloc]init]; popRecognizer.delegate=self; popRecognizer.maximumNumberOfTouches=1; [gestureViewaddGestureRecognizer:popRecognizer]; _navT=[[NavigationInteractiveTransitionalloc]initWithViewController:self.navigationController]; [popRecognizeraddTarget:_navTaction:@selector(handleControllerPop:)];
UIGestureRecognizerDelegate代理方法gestureRecognizerShouldBegin
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer{
//记录当前是是否是通过手势滑动回去
[[NSUserDefaultsstandardUserDefaults]setObject:[NSNumbernumberWithBool:YES]forKey:@"isGesturePop"];
/**
*这里有两个条件不允许手势执行,1、当前控制器为根控制器;2、如果这个push、pop动画正在执行(私有属性)
*/
returnself.navigationController.viewControllers.count!=1&&![[self.navigationControllervalueForKey:@"_isTransitioning"]boolValue];
}
需要依赖的两个类源码
NavigationInteractiveTransition.h
#import@classUIViewController,UIPercentDrivenInteractiveTransition; @interfaceNavigationInteractiveTransition:NSObject -(instancetype)initWithViewController:(UIViewController*)vc; -(void)handleControllerPop:(UIPanGestureRecognizer*)recognizer; -(UIPercentDrivenInteractiveTransition*)interactivePopTransition; @end
NavigationInteractiveTransition.m
#import"NavigationInteractiveTransition.h"
#import"PopAnimation.h"
@interfaceNavigationInteractiveTransition()
@property(nonatomic,weak)UINavigationController*vc;
@property(nonatomic,strong)UIPercentDrivenInteractiveTransition*interactivePopTransition;
@property(nonatomic,strong)UIImageView*barImageView;
@end
@implementationNavigationInteractiveTransition
-(instancetype)initWithViewController:(UIViewController*)vc
{
self=[superinit];
if(self){
self.vc=(UINavigationController*)vc;
self.vc.delegate=self;
}
returnself;
}
/**
*我们把用户的每次Pan手势操作作为一次pop动画的执行
*/
-(void)handleControllerPop:(UIPanGestureRecognizer*)recognizer{
/**
*interactivePopTransition就是我们说的方法2返回的对象,我们需要更新它的进度来控制Pop动画的流程,我们用手指在视图中的位置与视图宽度比例作为它的进度。
*/
CGFloatprogress=[recognizertranslationInView:recognizer.view].x/recognizer.view.bounds.size.width;
[self.vc.navigationBarsetBackgroundImage:[UIImagenew]forBarMetrics:UIBarMetricsDefault];
self.vc.navigationBar.shadowImage=[UIImagenew];
self.barImageView=self.vc.navigationBar.subviews.firstObject;
CGFloatalpha=[[[NSUserDefaultsstandardUserDefaults]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=[[UIPercentDrivenInteractiveTransitionalloc]init];
/**
*告诉控制器开始执行pop的动画
*/
[self.vcpopViewControllerAnimated:YES];
}
elseif(recognizer.state==UIGestureRecognizerStateChanged){
/**
*更新手势的完成进度
*/
[self.interactivePopTransitionupdateInteractiveTransition:progress];
}
elseif(recognizer.state==UIGestureRecognizerStateEnded||recognizer.state==UIGestureRecognizerStateCancelled){
/**
*手势结束时如果进度大于一半,那么就完成pop操作,否则重新来过。
*/
if(progress>0.5){
[self.interactivePopTransitionfinishInteractiveTransition];
self.barImageView.alpha=0;;
}
else{
[self.interactivePopTransitioncancelInteractiveTransition];
}
self.interactivePopTransition=nil;
}
}
-(id)navigationController:(UINavigationController*)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController*)fromVC
toViewController:(UIViewController*)toVC{
/**
*方法1中判断如果当前执行的是Pop操作,就返回我们自定义的Pop动画对象。
*/
if(operation==UINavigationControllerOperationPop)
return[[PopAnimationalloc]init];
returnnil;
}
-(id)navigationController:(UINavigationController*)navigationController
interactionControllerForAnimationController:(id)animationController{
/**
*方法2会传给你当前的动画对象animationController,判断如果是我们自定义的Pop动画对象,那么就返回interactivePopTransition来监控动画完成度。
*/
if([animationControllerisKindOfClass:[PopAnimationclass]])
returnself.interactivePopTransition;
returnnil;
}
@end
PopAnimation.h
#import#import @interfacePopAnimation:NSObject @end
PopAnimation.m
#import"PopAnimation.h" @interfacePopAnimation() @property(nonatomic,strong)idtransitionContext; @end @implementationPopAnimation -(NSTimeInterval)transitionDuration:(id )transitionContext{ //这个方法返回动画执行的时间 return0.25; } /** *transitionContext你可以看作是一个工具,用来获取一系列动画执行相关的对象,并且通知系统动画是否完成等功能。 */ -(void)animateTransition:(id )transitionContext{ /** *获取动画来自的那个控制器 */ UIViewController*fromViewController=[transitionContextviewControllerForKey:UITransitionContextFromViewControllerKey]; /** *获取转场到的那个控制器 */ UIViewController*toViewController=[transitionContextviewControllerForKey:UITransitionContextToViewControllerKey]; /** *转场动画是两个控制器视图时间的动画,需要一个containerView来作为一个“舞台”,让动画执行。 */ UIView*containerView=[transitionContextcontainerView]; [containerViewinsertSubview:toViewController.viewbelowSubview:fromViewController.view]; NSTimeIntervalduration=[selftransitionDuration:transitionContext]; /** *执行动画,我们让fromVC的视图移动到屏幕最右侧 */ [UIViewanimateWithDuration:durationanimations:^{ fromViewController.view.transform=CGAffineTransformMakeTranslation([UIScreenmainScreen].bounds.size.width,0); }completion:^(BOOLfinished){ /** *当你的动画执行完成,这个方法必须要调用,否则系统会认为你的其余任何操作都在动画执行过程中。 */ [transitionContextcompleteTransition:!transitionContext.transitionWasCancelled]; }]; } -(void)animationDidStop:(CATransition*)animfinished:(BOOL)flag{ [_transitionContextcompleteTransition:!_transitionContext.transitionWasCancelled]; } @end
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。