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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。