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];
}