• Stars
    star
    242
  • Rank 167,048 (Top 4 %)
  • Language
    Objective-C
  • License
    MIT License
  • Created over 6 years ago
  • Updated over 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

NNNavigationBar 实现导航条背景渐变过渡动画的轻量级框架

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。