iOS实现导航栏透明示例代码
程序员文章站
2023-12-20 12:20:10
在最近一个项目中碰到这样一个场景,在被push进来的一个页面设置导航栏透明,且要求控制对tableview组的头视图进行悬停显示,nav随着tableview偏移量改变透明...
在最近一个项目中碰到这样一个场景,在被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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。