导航栏隐藏的平滑切换

来源:互联网 发布:视频后期编辑软件 编辑:程序博客网 时间: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
原创粉丝点击