Skip to content

amisare/NNNavigationBar

Repository files navigation

NNNavigationBar

GitHub release CocoaPods CocoaPods GitHub license

本库用于实现UINavigationBar背景渐变过渡动画。

可能会遇到的问题

UINavigationBar 上的一个系统 bug ( An apple bug on the UINavigationBar)

bug 描述:导航右滑返回手势,概率性的导致返回以后页面的 rightBarButtonItem 的 tintColor 颜色变浅, bug 现象如下:

wx20181226-142113

bug 代码:

  • 在 viewDidLoad 中设置 rightBarButtonItem 会导致 bug 产生。bug 是概率性发生的,不易复现。
    override func viewDidLoad() {
        super.viewDidLoad()

        // 在 viewDidLoad 中设置 rightBarButtonItem
        self.navigationItem.rightBarButtonItem = UIBarButtonItem.init(title: "Next", style: .plain, target: self, action: #selector(pushNextViewController))
        self.view.backgroundColor = UIColor.white
        self.title = "Title" + " " + "\(self.page)"
    }

    @objc public func pushNextViewController() {
        let vc = self.nextViewController;
        vc.page = self.page + 1
        self.navigationController?.pushViewController(vc, animated: true)
    }

bug 解决:

  • 方式2:在 viewWillAppear 中设置 rightBarButtonItem 。
    override func viewDidLoad() {
        super.viewDidLoad()
        
       // 将 rightBarButtonItem 设置移至 viewWillAppear
       // self.navigationItem.rightBarButtonItem = UIBarButtonItem.init(title: "Next", style: .plain, target: self, action: #selector(pushNextViewController))
        self.view.backgroundColor = UIColor.white
        self.title = "Title" + " " + "\(self.page)"
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
       // 在 viewWillAppear 中设置 rightBarButtonItem
        self.navigationItem.rightBarButtonItem = UIBarButtonItem.init(title: "Next", style: .plain, target: self, action: #selector(pushNextViewController))
    }
    
    @objc public func pushNextViewController() {
        let vc = self.nextViewController;
        vc.page = self.page + 1
        self.navigationController?.pushViewController(vc, animated: true)
    }

bug 工程源码:UINavigationBarBug

效果

ColorTransition ImageTransition

介绍

NNNavigationBar是实现导航条背景渐变过渡动画的轻量级代码库。

实现

  • 代码库通过Category/Method Swizzling方式hook UINavigationBar的方法调用,实现导航条背景渐变过渡动画。

轻量

  • 仅对UINavigationBar进行了Method Swizzling方法混淆。不涉及其它类的方法混淆,如UIViewController、UINavigationController等。
  • 仅对UINavigationBar/UINavigationItem进行了必要的属性关联。

原理



                              UINavigationItem (category_xxx)
                                           |
                                           |
                                           V
                                           ①  
                                     add [.nn_xxx]
                                           |                         UIViewController
                                           |  ------------------->  [.navigationItem]
                                                                             |
                                                                             |
                                                                             V
                                                                             ② 
                                                               set vcn.navigationItem.nn_xxx
                                                                             |
                                                                             |
                                                                             |
                                 UINavigationController                      V
                                       vc stack                              ③            
                                 |        vcn        | <----- navigationController push/pop vcn
                                 |        ...        |                       |
                                 |        vc1        |                       |
                                 |        vc0        |                       |          
                                                                             |
     UINavigationBar                                                         |
-----------------------                                                      |
| <——    title        |                                                      |
-----------------------                                                      |
           |                                                                 |
           |                     UINavigationBar.Items                       V
           |        ④-②              item stack                           ④-①
           |<--- update Bar --- | vcn.navigationItem | <--- navigationBar push/pop vcn.navigationItem
           |          |         |        ...         |                       |
           |          |         | vc2.navigationItem |                       |
           |          |         | vc1.navigationItem |                       |
           |          |         | vc0.navigationItem |                       |
           |          |                                                      |
           |          |                        ④-③                          |
           |          |--------------------->  hook  <-----------------------|
           |                                    |
           |                                    |
           |                                    |
           |             ⑤                     |
           |<--- update Bar [.nn_xx] -----------|
                                                      
  1. 使用runtime在UINavigationItem的Category中添加属性[.nn_xx]。
  2. 每个UIViewController中都拥有一个UINavigationItem属性navigationItem,在UIViewController中修改navigationItem对象的属性[.nn_xx]。
  3. 在UINavigationController push/pop UIViewController时,会将UIViewController的navigationItem对象 push/pop 给UINavigationBar。
  4. 通过Method Swizzling方式hook UINavigationBar方法调用,获得对应方法的调用时机。
  5. 在合适的时刻,UINavigationBar取得navigationItem对象中的属性[.nn_xx],更新UINavigationBar状态(本代码库实现了背景的平滑渐变过渡)。

使用

  1. 导入头文件
#import "NNNavigationBar.h"
  1. 颜色渐变过渡
- (void)viewDidLoad {
    [super viewDidLoad];
    // 去除系统背景
    [self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
    [self.navigationController.navigationBar setShadowImage:[UIImage new]];
    // 显示自定义背景
    self.navigationController.navigationBar.nn_backgroundViewHidden = false;
    // 设置背景颜色
    self.navigationItem.nn_backgroundColor = [UIColor orangeColor];
}
  1. 图片渐变过渡
- (void)viewDidLoad {
    [super viewDidLoad];
    // 去除系统背景
    [self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
    [self.navigationController.navigationBar setShadowImage:[UIImage new]];
    // 显示自定义背景
    self.navigationController.navigationBar.nn_backgroundViewHidden = false;
    // 设置背景图片
    self.navigationItem.nn_backgroundImage = [UIImage imageNamed:xx_image];
}
  1. 更多使用,详见demo

安装

通过 CocoaPods 集成

安装最新版的 CocoaPods:

$ gem install cocoapods

podfile 中添加:

pod 'NNNavigationBar', '~> 2.7.3'

然后在终端执行:

$ pod install

如安装失败,提示:

[!] Unable to find a specification for `NNNavigationBar`

尝试使用命令:

pod install --repo-update

通过 Carthage 集成

Carthage 是一个去中心化的依赖管理器,用于构建依赖和提供二进制 Framework 。

可以通过以下 Homebrew 命令安装 Carthage :

$ brew update
$ brew install carthage

通过 Carthage 将 NNNavigationBar 集成到 Xcode 项目中,需要在 Cartfile 中添加:

github "amisare/NNNavigationBar" ~> 2.7.3

执行 carthage 构建 Framework ,并将 NNNavigationBar.framework 添加到 Xcode 项目中。

系统要求

  • iOS 8.0+

鸣谢

许可证

NNNavigationBar 是基于 MIT 许可证下发布的,详情参见 LICENSE。