4月:阅读WRNavigationBar源码

iOS动态改变导航栏透明度和颜色(WRNavigationBar)

github: https://github.com/wangrui460/WRNavigationBar

需求:项目需要一些透明导航栏,然后滑动效果,自己使用系统实现后,发现有一些细节体验不是很好。所以打算集成WRNavigationBar来优化用户体验,但是WRNavigationBar已经1年多没更新了(fix:有一些问题存在,入侵性太强)。
so,集成前理解实现,修改它下。

1.使用:

手动拖入 将 WRNavigationBar 文件夹拽入项目中,导入头文件:#import "WRNavigationBar.h",自定义导航栏需要导入 "WRCustomNavigationBar.h"

Use (以下方式不再适用自定义导航栏,自定义导航栏的使用方式请查看Demo)

✨✨ 一定要看 Demo 中的 AppDelegate 文件 ✨✨

// 设置是 全局使用WRNavigationBar,还是局部使用WRNavigationBar,目前默认是全局使用 (局部使用待开发)
[WRNavigationBar wr_widely];
// WRNavigationBar 不会对 blackList 中的控制器有影响
[WRNavigationBar wr_setBlacklist:@[@"SpecialController",
                                                            @"TZPhotoPickerController",
                                                            @"TZGifPhotoPreviewController",
                                                            @"TZAlbumPickerController",
                                                            @"TZPhotoPreviewController",
                                                            @"TZVideoPlayerController"]];

// 一行代码搞定导航栏颜色
[self wr_setNavBarBarTintColor:[UIColor whiteColor]];
// 一行代码搞定导航栏透明度
[self wr_setNavBarBackgroundAlpha:alpha];
// 一行代码搞定导航栏两边按钮颜色
[self wr_setNavBarTintColor:[UIColor whiteColor]];
// 一行代码搞定导航栏上标题颜色
[self wr_setNavBarTitleColor:[UIColor whiteColor]];
// 一行代码搞定状态栏是 default 还是 lightContent
[self wr_setStatusBarStyle:UIStatusBarStyleLightContent];
// 一行代码搞定导航栏底部分割线是否隐藏
[self wr_setNavBarShadowImageHidden:YES];

// 设置导航栏默认的背景颜色
[WRNavigationBar wr_setDefaultNavBarBarTintColor:MainNavBarColor];
// 设置导航栏所有按钮的默认颜色
[WRNavigationBar wr_setDefaultNavBarTintColor:[UIColor whiteColor]];
// 设置导航栏标题默认颜色
[WRNavigationBar wr_setDefaultNavBarTitleColor:[UIColor whiteColor]];
// 统一设置状态栏样式
[WRNavigationBar wr_setDefaultStatusBarStyle:UIStatusBarStyleLightContent];
// 如果需要设置导航栏底部分割线隐藏,可以在这里统一设置
[WRNavigationBar wr_setDefaultNavBarShadowImageHidden:YES];

2.项目集成:

对一个开发3年多的项目,直接拉取集进去后,果然(入侵性太强,导致App整体的导航栏效果,以及对导航栏控制的处理,都出现了一些问题),然后就开始解决这些问题,确实入侵性太强,并且有大量问题存在,所以我打算剥离真正对项目有用的代码,一些导航栏处理等,还是保持用系统。

3.项目源码理解:

#import 
@class WRCustomNavigationBar;

@interface WRNavigationBar : UIView
+ (CGFloat)navBarBottom;
+ (CGFloat)tabBarTop;
+ (CGFloat)screenWidth;
+ (CGFloat)screenHeight;
@end


#pragma mark - Default
@interface WRNavigationBar (WRDefault)

/// 局部使用该库       待开发
//+ (void)wr_local;
/// 广泛使用该库       default 暂时是默认, wr_local 完成后,wr_local就会变成默认
+ (void)wr_widely;

/// 局部使用该库时,设置需要用到的控制器      待开发
//+ (void)wr_setWhitelist:(NSArray *)list;
/// 广泛使用该库时,设置需要屏蔽的控制器
+ (void)wr_setBlacklist:(NSArray *)list;

/** set default barTintColor of UINavigationBar */
+ (void)wr_setDefaultNavBarBarTintColor:(UIColor *)color;

/** set default barBackgroundImage of UINavigationBar */
/** warning: wr_setDefaultNavBarBackgroundImage is deprecated! place use WRCustomNavigationBar */
//+ (void)wr_setDefaultNavBarBackgroundImage:(UIImage *)image;

/** set default tintColor of UINavigationBar */
+ (void)wr_setDefaultNavBarTintColor:(UIColor *)color;

/** set default titleColor of UINavigationBar */
+ (void)wr_setDefaultNavBarTitleColor:(UIColor *)color;

/** set default statusBarStyle of UIStatusBar */
+ (void)wr_setDefaultStatusBarStyle:(UIStatusBarStyle)style;

/** set default shadowImage isHidden of UINavigationBar */
+ (void)wr_setDefaultNavBarShadowImageHidden:(BOOL)hidden;

@end



#pragma mark - UINavigationBar
@interface UINavigationBar (WRAddition) 

/** 设置导航栏所有BarButtonItem的透明度 */
- (void)wr_setBarButtonItemsAlpha:(CGFloat)alpha hasSystemBackIndicator:(BOOL)hasSystemBackIndicator;

/** 设置导航栏在垂直方向上平移多少距离 */
- (void)wr_setTranslationY:(CGFloat)translationY;

/** 获取当前导航栏在垂直方向上偏移了多少 */
- (CGFloat)wr_getTranslationY;

@end




#pragma mark - UIViewController
@interface UIViewController (WRAddition)

/** record current ViewController navigationBar backgroundImage */
/** warning: wr_setDefaultNavBarBackgroundImage is deprecated! place use WRCustomNavigationBar */
//- (void)wr_setNavBarBackgroundImage:(UIImage *)image;
- (UIImage *)wr_navBarBackgroundImage;

/** record current ViewController navigationBar barTintColor */
- (void)wr_setNavBarBarTintColor:(UIColor *)color;
- (UIColor *)wr_navBarBarTintColor;

/** record current ViewController navigationBar backgroundAlpha */
- (void)wr_setNavBarBackgroundAlpha:(CGFloat)alpha;
- (CGFloat)wr_navBarBackgroundAlpha;

/** record current ViewController navigationBar tintColor */
- (void)wr_setNavBarTintColor:(UIColor *)color;
- (UIColor *)wr_navBarTintColor;

/** record current ViewController titleColor */
- (void)wr_setNavBarTitleColor:(UIColor *)color;
- (UIColor *)wr_navBarTitleColor;

/** record current ViewController statusBarStyle */
- (void)wr_setStatusBarStyle:(UIStatusBarStyle)style;
- (UIStatusBarStyle)wr_statusBarStyle;

/** record current ViewController navigationBar shadowImage hidden */
- (void)wr_setNavBarShadowImageHidden:(BOOL)hidden;
- (BOOL)wr_navBarShadowImageHidden;

/** record current ViewController custom navigationBar */
/** warning: wr_setDefaultNavBarBackgroundImage is deprecated! place use WRCustomNavigationBar */
//- (void)wr_setCustomNavBar:(WRCustomNavigationBar *)navBar;

@end

实现导航栏透明渐变

// set navigationBar barTintColor
- (void)wr_setBackgroundColor:(UIColor *)color
{
    if (self.backgroundView == nil)
    {
        // add a image(nil color) to _UIBarBackground make it clear
        [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
        self.backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), kWRNavBarBottom)];
        // _UIBarBackground is first subView for navigationBar
        [self.subviews.firstObject insertSubview:self.backgroundView atIndex:0];
    }
    self.backgroundView.backgroundColor = color;
}

// set _UIBarBackground alpha (_UIBarBackground subviews alpha <= _UIBarBackground alpha)
- (void)wr_setBackgroundAlpha:(CGFloat)alpha
{
    UIView *barBackgroundView = self.subviews.firstObject;
    barBackgroundView.alpha = alpha;
}
对系统导航栏一些控制处理:push,pop,返回手势

我们都知道,导航栏是属于导航控制器的,一个导航栏不可能出现两个颜色,那么右滑突兀怎么解决呢?两个方法,一个方法是自定义导航栏(后面会说),另一个方法是改变导航栏颜色,我们假设当前控制器为fromVC,返回的控制器为toVC,如果可以实现从 fromVC 右滑到 toVC 导航栏颜色渐变那么问题就解决了!但是导航栏只有一个颜色啊~~~怎么办?
同样,可以通过加一层的方法来解决。我们可以记录一下 fromVC消失前对应的导航栏颜色 和 toVC 当前的导航栏颜色,然后根据右滑进度percentComplete,来计算渐变色,这样问题就解决了!
记录ViewController对应导航栏的颜色和透明度

// navigationBar barTintColor
- (UIColor *)wr_navBarBarTintColor
{
    UIColor *barTintColor = (UIColor *)objc_getAssociatedObject(self, &kWRNavBarBarTintColorKey);
    return (barTintColor != nil) ? barTintColor : [UIColor defaultNavBarBarTintColor];
}
- (void)wr_setNavBarBarTintColor:(UIColor *)color
{
    objc_setAssociatedObject(self, &kWRNavBarBarTintColorKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    if ([[self wr_customNavBar] isKindOfClass:[UINavigationBar class]])
    {
        UINavigationBar *navBar = (UINavigationBar *)[self wr_customNavBar];
        [navBar wr_setBackgroundColor:color];
    }
    else
    {
        if ([self pushToCurrentVCFinished] == YES && [self pushToNextVCFinished] == NO) {
            [self.navigationController setNeedsNavigationBarUpdateForBarTintColor:color];
        }
    }
}

// navigationBar _UIBarBackground alpha
- (CGFloat)wr_navBarBackgroundAlpha
{
    id barBackgroundAlpha = objc_getAssociatedObject(self, &kWRNavBarBackgroundAlphaKey);
    return (barBackgroundAlpha != nil) ? [barBackgroundAlpha floatValue] : [UIColor defaultNavBarBackgroundAlpha];
    
}
- (void)wr_setNavBarBackgroundAlpha:(CGFloat)alpha
{
    objc_setAssociatedObject(self, &kWRNavBarBackgroundAlphaKey, @(alpha), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    if ([[self wr_customNavBar] isKindOfClass:[UINavigationBar class]])
    {
        UINavigationBar *navBar = (UINavigationBar *)[self wr_customNavBar];
        [navBar wr_setBackgroundAlpha:alpha];
    }
    else
    {
        if ([self pushToCurrentVCFinished] == YES && [self pushToNextVCFinished] == NO) {
            [self.navigationController setNeedsNavigationBarUpdateForBarBackgroundAlpha:alpha];
        }
    }
}

交换系统方法 _updateInteractiveTransition(监控右滑返回手势的进度)

// swizzling system method: _updateInteractiveTransition
- (void)wr_updateInteractiveTransition:(CGFloat)percentComplete
{
    UIViewController *fromVC = [self.topViewController.transitionCoordinator viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [self.topViewController.transitionCoordinator viewControllerForKey:UITransitionContextToViewControllerKey];
    [self updateNavigationBarWithFromVC:fromVC toVC:toVC progress:percentComplete];
    
    [self wr_updateInteractiveTransition:percentComplete];
}

根据 fromVC 与 toVC 的导航栏颜色 配合 返回手势进度计算渐变色

+ (UIColor *)middleColor:(UIColor *)fromColor toColor:(UIColor *)toColor percent:(CGFloat)percent
{
    CGFloat fromRed = 0;
    CGFloat fromGreen = 0;
    CGFloat fromBlue = 0;
    CGFloat fromAlpha = 0;
    [fromColor getRed:&fromRed green:&fromGreen blue:&fromBlue alpha:&fromAlpha];
    
    CGFloat toRed = 0;
    CGFloat toGreen = 0;
    CGFloat toBlue = 0;
    CGFloat toAlpha = 0;
    [toColor getRed:&toRed green:&toGreen blue:&toBlue alpha:&toAlpha];
    
    CGFloat newRed = fromRed + (toRed - fromRed) * percent;
    CGFloat newGreen = fromGreen + (toGreen - fromGreen) * percent;
    CGFloat newBlue = fromBlue + (toBlue - fromBlue) * percent;
    CGFloat newAlpha = fromAlpha + (toAlpha - fromAlpha) * percent;
    return [UIColor colorWithRed:newRed green:newGreen blue:newBlue alpha:newAlpha];
}

改变导航栏颜色和透明度

- (void)updateNavigationBarWithFromVC:(UIViewController *)fromVC toVC:(UIViewController *)toVC progress:(CGFloat)progress
{
    // change navBarBarTintColor
    UIColor *fromBarTintColor = [fromVC wr_navBarBarTintColor];
    UIColor *toBarTintColor = [toVC wr_navBarBarTintColor];
    UIColor *newBarTintColor = [UIColor middleColor:fromBarTintColor toColor:toBarTintColor percent:progress];
    [self setNeedsNavigationBarUpdateForBarTintColor:newBarTintColor];
    
    // change navBarTintColor
    UIColor *fromTintColor = [fromVC wr_navBarTintColor];
    UIColor *toTintColor = [toVC wr_navBarTintColor];
    UIColor *newTintColor = [UIColor middleColor:fromTintColor toColor:toTintColor percent:progress];
    [self setNeedsNavigationBarUpdateForTintColor:newTintColor];
    
    // change navBarTitleColor
    UIColor *fromTitleColor = [fromVC wr_navBarTitleColor];
    UIColor *toTitleColor = [toVC wr_navBarTitleColor];
    UIColor *newTitleColor = [UIColor middleColor:fromTitleColor toColor:toTitleColor percent:progress];
    [self setNeedsNavigationBarUpdateForTitleColor:newTitleColor];
    
    // change navBar _UIBarBackground alpha
    CGFloat fromBarBackgroundAlpha = [fromVC wr_navBarBackgroundAlpha];
    CGFloat toBarBackgroundAlpha = [toVC wr_navBarBackgroundAlpha];
    CGFloat newBarBackgroundAlpha = [UIColor middleAlpha:fromBarBackgroundAlpha toAlpha:toBarBackgroundAlpha percent:progress];
    [self setNeedsNavigationBarUpdateForBarBackgroundAlpha:newBarBackgroundAlpha];
}

你可能感兴趣的:(4月:阅读WRNavigationBar源码)