UINavigationExtension 是为 iOS 应用设计的一个简单、易用的导航栏处理框架。框架对现有代码入侵非常小,只需要简单的几个方法调用就可以满足大部分的应用场景。UINavigationExtension 和 示例程序代码 都已经适配暗黑模式(Dark Mode)。
🎉 预览 & 暗黑模式
🌟 开始使用
下载 UINavigationExtension 示例程序代码。
使用 CocoaPods 安装
使用 CocoaPods 将 UINavigationExtension 集成到 Xcode 项目中,需要在 Podfile
中指定:
pod 'UINavigationExtension'
或者
pod 'UINavigationExtension', ~> 2.3.14
使用 Carthage 安装
Carthage 是一个去中心化的包管理器,它构建依赖项并为您提供二进制框架。 要集成 UINavigationExtension,请将以下内容添加到您的 Cartfile
文件中:
github "l1Dan/UINavigationExtension"
或者
github "l1Dan/UINavigationExtension" ~> 2.3.14
🌈 要求
UINavigationExtension Version | Minimum iOS Target | Minimum macOS Target | Minimum watchOS Target | Minimum tvOS Target | Notes |
---|---|---|---|---|---|
2.x | iOS 11 | macOS 10.15 | n/a | n/a | macOS: macCatalyst |
👏 功能
基本功能
✅ 修改返回按钮箭头颜色
✅ 修改导航栏标题颜色
✅ 修改导航栏背景颜色
✅ 修改导航栏背景图片
✅ 设置导航栏透明
✅ 设置导航栏半透明
✅ 修改导航栏底部线条颜色
✅ 修改导航栏底部线条颜色图片
✅ 自定义返回按钮图片
✅ 自定义返回按钮
高级功能
✅ 禁用滑动返回手势
✅ 启用全屏滑动返回手势
✅ 导航栏返回事件拦截
✅ 重定向任一控制器跳转
✅ 导航栏点击事件穿透到底部
✅ 动态修改导航栏样式
✅ 更新导航栏样式
🍽 使用
所有对导航栏外观的修改都是基于视图控制器 UIViewController
修改的,而不是基于导航控制器 UINavigationController
修改,这种设计逻辑更加符合实际应用场景。也就是自己所在的导航栏的外观自己管理就好。
💉 导入头文件#import <UINavigationExtension/UINavigationExtension.h>
💉 使用之前需要先注册需要修改的导航控制器,以FeatureNavigationController
为例:
[UENavigationBar registerStandardAppearanceForNavigationControllerClass:[FeatureNavigationController class]];
注意:
👉 使用之前需要先注册导航控制器,注册之后对导航栏的修改才会生效,也仅限于修改本类所管理的视图控制器,对于子类导航控制器所管理的视图控制器是不会生效的,这样可以有效避免框架污染到其他的导航控制器,保持“谁使用,谁注册”的原则。🚫 不要直接注册UINavigationController
,这个影响范围比较太广,建议创建一个UINavigationController
的子类,对这个类进行注册。🚫 不要使用系统导航栏隐藏、显示方法,setNavigationBarHidden:
、setNavigationBarHidden:animated
、setHidden:
。🚫 不要使用系统导航栏修改透明度。🚫 不要使用系统导航栏或导航控制器appearance
相关属性修改。🚫 不要使用全局edgesForExtendedLayout
修改。🚫 不要使用<UIGestureRecognizerDelegate>
相关方法禁用手势返回。💉 一句话“不要直接操作导航栏或者导航控制器,把这些都交给UINavigationExtension
处理吧“。
建议:除非你非常明白修改全局性东西的后果,否则不要修改,这么做的原因就是为了减少走一些弯路!
🍻 基本功能
修改返回按钮箭头颜色
导航栏返回按钮颜色默认使用系统蓝色 [UIColor systemBlueColor]
,要改变返回按钮颜色可以使用以下方式配合:
// 全局统一修改,不会覆盖基于视图控制器修改
UENavigationBarAppearance.standardAppearance.tintColor = [UIColor redColor];
// 基于视图控制器修改
- (UIColor *)ue_barTintColor {
return self.isDarkMode ? [UIColor whiteColor] : [UIColor blackColor];
}
修改导航栏标题颜色
- (NSDictionary<NSAttributedStringKey,id> *)ue_titleTextAttributes {
return @{NSForegroundColorAttributeName: [self ue_barTintColor]};
}
修改导航栏背景颜色
- (UIColor *)ue_navigationBarBackgroundColor {
return [UIColor customDarkGrayColor];
}
修改导航栏背景图片
- (UIImage *)ue_navigationBarBackgroundImage {
return UIImage.navigationBarBackgorundImage;
}
设置导航栏透明
- (UIColor *)ue_navigationBarBackgroundColor {
return [UIColor clearColor];
}
设置导航栏半透明
- (BOOL)ue_useSystemBlurNavigationBar {
return YES;
}
修改导航栏底部线条颜色
- (UIColor *)ue_shadowImageTintColor {
return [UIColor redColor];
}
修改导航栏底部线条颜色图片
- (UIColor *)ue_shadowImageTintColor {
return [UIColor redColor];
}
修改导航栏底部线条颜色图片
- (UIImage *)ue_shadowImage {
return [UIImage imageNamed:@"NavigationBarShadowImage"];
}
自定义返回按钮图片
- (UIImage *)ue_backImage {
return [UIImage imageNamed:@"NavigationBarBack"];
}
自定义返回按钮
- (UIView *)ue_backButtonCustomView {
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setTitle:@"😋" forState:UIControlStateNormal];
[backButton setImage:[UIImage imageNamed:@"NavigationBarBack"] forState:UIControlStateNormal];
[backButton setTitleColor:UIColor.customDarkGrayColor forState:UIControlStateNormal];
return backButton;
}
🍺 高级功能
禁用滑动返回手势
- (BOOL)ue_disableInteractivePopGesture {
return YES;
}
启用全屏滑动返回手势
- 局部有效(在所处页面设置)
- (BOOL)ue_enableFullScreenInteractivePopGesture {
return YES;
}
- 全局有效(在注册导航栏之前设置)
UINavigationExtensionFullscreenPopGestureEnable = YES;
导航栏返回事件拦截
需要遵守协议 <UINavigationControllerCustomizable>
,实现代理方法:
- (BOOL)navigationController:(__kindof UINavigationController *)navigationController willPopViewControllerUsingInteractiveGesture:(BOOL)usingGesture {
// TODO...
return YES;
}
- 拦截点击返回按钮事件 & 手势返回事件
- 拦截点击返回按钮事件
- 拦截手势返回事件
- (BOOL)navigationController:(__kindof UINavigationController *)navigationController willPopViewControllerUsingInteractiveGesture:(BOOL)usingGesture {
if (self.currentItemType == EventInterceptItemTypeBoth) { // 拦截点击返回按钮事件 & 手势返回事件
[self showAlertController];
return NO;
}
if (self.currentItemType == EventInterceptItemTypeBackButton) { // 拦截点击返回按钮事件
if (!usingGesture) {
[self showAlertController];
return NO;
}
}
if (self.currentItemType == EventInterceptItemTypePopGesture) { // 拦截手势返回事件
if (usingGesture) {
[self showAlertController];
return NO;
}
}
return YES;
}
自定义返回按钮事件拦截需要调用方法:[self.navigationController ue_triggerSystemBackButtonHandler];
重定向任一控制器跳转
- 以重定向到
RandomColorViewController
为例,如果之前有 Push 过RandomColorViewController
的实例,则最后会跳转到实例中,如果没有则会调用block
,如果block == NULL
或者return nil;
则重定向跳转不会发生。 - 执行重定向操作之后,并不会直接跳转到对应的视图控制器,如果需要
跳转
操作,可以调用popViewControllerAnimated:
、使用手势返回
、点击返回按钮返回
。
[self.navigationController ue_redirectViewControllerClass:[RandomColorViewController class] createViewControllerUsingBlock:^__kindof UIViewController * _Nonnull {
return [[RandomColorViewController alloc] init];
}];
注意: 执行上面代码之后并不会立即跳转,下面代码可以实现立即跳转:
[self.navigationController ue_redirectViewControllerClass:[RandomColorViewController class] createViewControllerUsingBlock:^__kindof UIViewController * _Nonnull {
return [[RandomColorViewController alloc] init];
}];
[self.navigationController popViewControllerAnimated:YES];
上面代码大意为:首先查找 self.navigationController.ViewConrollers
是否存在一个类型为 [RandomColorViewController class]
的实例对象,如果存在则重定向到此视图控制器,没有则使用 [[RandomColorViewController alloc] init]
来创建一个新的 [RandomColorViewController class]
的实例对象。
导航栏点击事件穿透到底部
- (BOOL)ue_hidesNavigationBar {
return YES;
}
动态修改导航栏样式
- (BOOL)ue_containerViewWithoutNavigtionBar {
return YES;
}
可以动态调整 ContainerView 透明度实现:self.ue_navigationBar.containerView.alpha = value
更新导航栏样式
[self ue_setNeedsNavigationBarAppearanceUpdate];
如果状态栏样式没有发生变化,请检查是否需要调用方法 [self setNeedsStatusBarAppearanceUpdate]
,或者在 UINavigationController
的子类中设置如下代码:
- (UIViewController *)childViewControllerForStatusBarStyle {
return self.topViewController;
}
- (UIViewController *)childViewControllerForStatusBarHidden {
return self.topViewController;
}
📄 协议
UINavigationExtension 框架是在 MIT 许可下发布的。详情请参见 LICENSE。