导航栏隐藏的平滑切换
来源:互联网 发布:视频后期编辑软件 编辑:程序博客网 时间:2024/06/10 09:30
最近项目要用到透明导航栏,如果只是单纯的将导航栏设置为隐藏,则在切换页面的时候过度就很生硬,体验很不好,网上搜索了好几个实例看了下,基本都是用runtime的黑魔法实现的,但是效果都没有达到我需要的效果,所以就综合几个示例,完成了下面的demo,切换效果还是很好,很平滑,达到了预期的效果。
本示例也是通过runtime黑魔法来实现的,这里做个记录,有需要的可以拿过去用,本篇会贴出全部的关键代码段
效果图
工程文件结构如下图
//// UINavigationController+SMA.h// navDemo//#import <UIKit/UIKit.h>@interface UINavigationController (SMAUI) <UINavigationBarDelegate,UINavigationControllerDelegate>/** 设置导航栏背景透明度 @param alpha 透明度的浮点值 */-(void)setNavigationBackground:(CGFloat)alpha;@end
//// UINavigationController+SMA.m// navDemo//#import "UINavigationController+SMA.h"#import "UIViewController+SMA.h"#import <objc/runtime.h>@implementation UINavigationController (SMAUI)//设置导航栏背景透明度-(void)setNavigationBackground:(CGFloat)alpha{ // 导航栏背景透明度设置 UIView *barBackgroundView = [[self.navigationBar subviews] objectAtIndex:0];// _UIBarBackground UIImageView *backgroundImageView = [[barBackgroundView subviews] objectAtIndex:0];// UIImageView //去掉导航栏下的黑线 UIView *shadowView = (UIView *)[barBackgroundView valueForKey:@"_shadowView"]; if (shadowView) { shadowView.alpha = alpha; } if (self.navigationBar.isTranslucent) { if (backgroundImageView != nil && backgroundImageView.image != nil) { barBackgroundView.alpha = alpha; } else { UIView *backgroundEffectView = [[barBackgroundView subviews] objectAtIndex:1];// UIVisualEffectView if (backgroundEffectView != nil) { backgroundEffectView.alpha = alpha; } } } else { barBackgroundView.alpha = alpha; }}+ (void)initialize { if (self == [UINavigationController self]) { // 交换方法 SEL originalSelector = NSSelectorFromString(@"_updateInteractiveTransition:"); SEL swizzledSelector = NSSelectorFromString(@"et__updateInteractiveTransition:"); Method originalMethod = class_getInstanceMethod([self class], originalSelector); Method swizzledMethod = class_getInstanceMethod([self class], swizzledSelector); method_exchangeImplementations(originalMethod, swizzledMethod); }}// 交换的方法,监控滑动手势- (void)et__updateInteractiveTransition:(CGFloat)percentComplete { [self et__updateInteractiveTransition:(percentComplete)]; UIViewController *topVC = self.topViewController; if (topVC != nil) { id<UIViewControllerTransitionCoordinator> coor = topVC.transitionCoordinator; if (coor != nil) { // 随着滑动的过程设置导航栏透明度渐变 CGFloat fromAlpha = [[coor viewControllerForKey:UITransitionContextFromViewControllerKey].navBarBgAlpha floatValue]; CGFloat toAlpha = [[coor viewControllerForKey:UITransitionContextToViewControllerKey].navBarBgAlpha floatValue]; CGFloat nowAlpha = fromAlpha + (toAlpha - fromAlpha) * percentComplete;// NSLog(@"from:%f, to:%f, now:%f",fromAlpha, toAlpha, nowAlpha); [self setNavigationBackground:nowAlpha]; } }}#pragma mark - UINavigationController Delegate- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { UIViewController *topVC = self.topViewController; if (topVC != nil) { id<UIViewControllerTransitionCoordinator> coor = topVC.transitionCoordinator; if (coor != nil) { [coor notifyWhenInteractionChangesUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context){ [self dealInteractionChanges:context]; }]; } }}- (void)dealInteractionChanges:(id<UIViewControllerTransitionCoordinatorContext>)context { if ([context isCancelled]) {// 自动取消了返回手势 NSTimeInterval cancelDuration = [context transitionDuration] * (double)[context percentComplete]; [UIView animateWithDuration:cancelDuration animations:^{ CGFloat nowAlpha = [[context viewControllerForKey:UITransitionContextFromViewControllerKey].navBarBgAlpha floatValue]; NSLog(@"自动取消返回到alpha:%f", nowAlpha); [self setNavigationBackground:nowAlpha]; }]; } else {// 自动完成了返回手势 NSTimeInterval finishDuration = [context transitionDuration] * (double)(1 - [context percentComplete]); [UIView animateWithDuration:finishDuration animations:^{ CGFloat nowAlpha = [[context viewControllerForKey: UITransitionContextToViewControllerKey].navBarBgAlpha floatValue]; NSLog(@"自动完成返回到alpha:%f", nowAlpha); [self setNavigationBackground:nowAlpha]; }]; }}#pragma mark - UINavigationBar Delegate- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item { if (self.viewControllers.count >= navigationBar.items.count) {// 点击返回按钮 UIViewController *popToVC = self.viewControllers[self.viewControllers.count - 1]; [self setNavigationBackground:[popToVC.navBarBgAlpha floatValue]]; }}- (void)navigationBar:(UINavigationBar *)navigationBar didPushItem:(UINavigationItem *)item { // push到一个新界面 [self setNavigationBackground:[self.topViewController.navBarBgAlpha floatValue]];}@end
//// UIViewController+SMA.h// navDemo//#import <UIKit/UIKit.h>///为系统的UIViewController动态增加属性@interface UIViewController (SMAUI)//vc的导航bar背景透明度@property (copy,nonatomic) NSString *navBarBgAlpha;@end
//// UIViewController+SMA.m// navDemo//#import "UIViewController+SMA.h"#import "UINavigationController+SMA.h"#import <objc/runtime.h>@implementation UIViewController (SMAUI)//属性对应的key 必须是C语言字符串static char *SMAUI = "SMAUI";-(void)setNavBarBgAlpha:(NSString *)navBarBgAlpha{ objc_setAssociatedObject(self, SMAUI, navBarBgAlpha, OBJC_ASSOCIATION_COPY_NONATOMIC); // 设置导航栏透明度(利用Category自己添加的方法) [self.navigationController setNavigationBackground:[navBarBgAlpha floatValue]];}-(NSString *)navBarBgAlpha{ return objc_getAssociatedObject(self, SMAUI);}@end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]; FirstViewController *vc1 = [[FirstViewController alloc]init]; UINavigationController *nav1 = [[UINavigationController alloc]initWithRootViewController:vc1]; nav1.tabBarItem = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemFavorites tag:1]; //设置导航栏的背景颜色和title颜色 nav1.navigationBar.tintColor = [UIColor grayColor]; [nav1.navigationBar setTintColor:[UIColor whiteColor]]; [nav1.navigationBar setBarTintColor:[UIColor grayColor]]; [nav1.navigationBar setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor],NSForegroundColorAttributeName,nil]]; nav1.navigationBar.shadowImage = [UIImage new]; SecondViewController *vc2 = [[SecondViewController alloc]init]; UINavigationController *nav2 = [[UINavigationController alloc]initWithRootViewController:vc2]; nav2.tabBarItem = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemContacts tag:2]; UITabBarController *tab = [[UITabBarController alloc]init]; [tab setViewControllers:@[nav1,nav2]]; self.window.rootViewController = tab; //设置状态栏字体为白色 [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault; [self.window makeKeyAndVisible]; return YES;}
//// FirstViewController.m// navDemo//#import "FirstViewController.h"#import "UIViewController+SMA.h"#import "SecondViewController.h"#import "ThirdViewController.h"@interface FirstViewController ()@end@implementation FirstViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor lightGrayColor]; self.title = @"First"; UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 200, 50)]; [btn setTitle:@"Next View" forState:UIControlStateNormal]; [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [btn addTarget:self action:@selector(toNextView) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn];}// 按钮响应- (void)toNextView { ThirdViewController *VC3 = [[ThirdViewController alloc] init]; [self.navigationController pushViewController:VC3 animated:YES];}- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.navigationController.navigationBar.subviews.firstObject.alpha = 1.0; self.navBarBgAlpha = @"1.0";}@end
//// SecondViewController.m// navDemo//#import "SecondViewController.h"#import "UIViewController+SMA.h"#import "ThirdViewController.h"@interface SecondViewController ()@end@implementation SecondViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor lightGrayColor]; UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 200, 50)]; [btn setTitle:@"Next View" forState:UIControlStateNormal]; [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [btn addTarget:self action:@selector(toNextView) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn];}// 按钮响应- (void)toNextView { ThirdViewController *VC3 = [[ThirdViewController alloc] init]; [self.navigationController pushViewController:VC3 animated:YES];}- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.navBarBgAlpha = @"0.0";}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}/*#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller.}*/@end
//// ThirdViewController.m// navDemo//#import "ThirdViewController.h"#import "UIViewController+SMA.h"#define sWidth [UIScreen mainScreen].bounds.size.width#define sHeight [UIScreen mainScreen].bounds.size.height@interface ThirdViewController ()<UITableViewDelegate,UITableViewDataSource>@property(nonatomic,strong) UITableView *tableView;@end@implementation ThirdViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor lightGrayColor]; [self.view addSubview:self.tableView]; }-(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear: YES]; self.navBarBgAlpha = @"0.0";}#pragma mark UITableViewDelegate-(void)scrollViewDidScroll:(UIScrollView *)scrollView{ CGFloat minAlphaOffset = -64; CGFloat maxAlphaOffset = 200; CGFloat offset = scrollView.contentOffset.y; CGFloat alpha = (offset - minAlphaOffset) / (maxAlphaOffset - minAlphaOffset); self.navBarBgAlpha = [NSString stringWithFormat:@"%f",alpha];}-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"reuseIdentifier"]; cell.textLabel.text = [NSString stringWithFormat:@"%ld",indexPath.row]; return cell;}-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{ CGFloat viewHeght = 150 * (sWidth / 320); UIView *topView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, sWidth, viewHeght)]; topView.backgroundColor = [UIColor colorWithRed:6/255.0 green:193/255.0 blue:174/255.0 alpha:1.0]; return topView;}-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1;}-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 30;}-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 50;}-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ return 150 * (sWidth / 320);}-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ [tableView deselectRowAtIndexPath:indexPath animated:YES];}-(UITableView *)tableView{ if (!_tableView) { _tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, -64, sWidth, sHeight + 64) style:UITableViewStyleGrouped]; _tableView.delegate = self; _tableView.dataSource = self; } return _tableView;}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}/*#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller.}*/@end
0 0
- 导航栏隐藏的平滑切换
- 导航栏的平滑显示和隐藏
- 切换页面隐藏导航栏出现黑条的问题
- 隐藏显示导航栏切换不流畅的问题
- iOS 完美解决导航栏在页面切换时隐藏与显示的动画
- 导航栏切换导航条的移动
- iOS导航栏切换界面时隐藏和显示
- iOS11导航栏在tabbar切换时动态隐藏
- iOS透明导航栏的平滑过渡(进阶版)
- iOS透明导航栏的平滑过渡(进阶版)
- iOS透明导航栏的平滑过渡(进阶版)
- sharepoint 2007 隐藏左侧的导航栏
- WPF Page页面导航栏的隐藏
- 如何隐藏导航栏下的线
- 滑动逐渐隐藏导航栏的实现
- 隐藏导航栏最底下的线条
- iOS隐藏导航栏下面的横线
- //隐藏导航栏的返回按钮
- 简单的使用SwipeRefreshLayout
- python第15天:异常
- Android color 平滑过渡计算
- Linux下如何查看哪些进程占用的CPU内存资源最多
- java http xml java通过http来访问一个xml文件的读取过程
- 导航栏隐藏的平滑切换
- 服务器选择Windows还是Linux
- 蓝桥杯
- MFC界面库BCGControlBar v25.2新版亮点:Dialogs和Grid控件等
- 二叉树的重要性质
- 面试常考--二叉树算法
- 360(2017春季笔试题)跑步
- VS2010-MFC:单文档左侧可停靠对话框(包含树控件)的实现
- iBet Win Jason Zhang & Power Station Concert Ticket(iBET Lucky Draw, iphone lucky draw casino, lucky