美文网首页iOS Developer
iOS给控制器定制导航栏

iOS给控制器定制导航栏

作者: AryCode | 来源:发表于2017-05-17 23:13 被阅读102次

最近因为项目的需要,需要设计类似与网易一样,每个控制器都能携带一个自己的导航栏,下面就是代码(打字太多,觉得自己都不是一个合格的程序猿,ps:本来有很多废话的,哈哈~~~).

IMG_3906.PNG

集成这种功能,只要导入如下图所示的文件,接下来你会发现的你的项目已经实现了类似如网易导航栏的效果,效果如下,我并没有在项目中对控制器本身做任何特殊的处理


3784FC4F-BE34-4B66-BABB-527BA0D5E8B4.png 2017-05-17 23_16_20.gif

下面说下思路:
1.代码1:

// UIViewController+ExtendNavigation.m
+ (void)load
{
    // viewWillAppear方法交换
    {
        IMP imp1 = class_getMethodImplementation([self class], @selector(viewWillAppear:));
        Method m1 = class_getInstanceMethod([self class], @selector(viewWillAppear:));
        Method m2 = class_getInstanceMethod([self class], @selector(viewWillAppear_QF:));
        BOOL result = class_addMethod([self class], @selector(viewWillAppear:), imp1, method_getTypeEncoding(m1));
        if (result != YES)
        {
            method_exchangeImplementations(m1, m2);
        }
    }
    
    // 交换导航栏标题的方法
    {
        IMP imp1 = class_getMethodImplementation([self class], @selector(setTitle:));
        Method m1 = class_getInstanceMethod([self class], @selector(setTitle:));
        Method m2 = class_getInstanceMethod([self class], @selector(setTitle_QF:));
        BOOL result = class_addMethod([self class], @selector(setTitle:), imp1, method_getTypeEncoding(m1));
        if (result != YES)
        {
            method_exchangeImplementations(m1, m2);
        }
    }
}

代码2:

- (void)viewWillAppear_QF:(BOOL)animated {
    [self viewWillAppear_QF:animated];
    
    if (self.loadNavigationBar)
    {
        NSLog(@"%@",self);
        // 自定义导航栏
        [self styleNavBar];
        self.navigationItem.viewController = self;
        __weak id weakSelf = self;
        self.navigationController.interactivePopGestureRecognizer.delegate = weakSelf;
    }
    self.loadNavigationBar = NO;
}

- (void)styleNavBar {
    [self.navigationController setNavigationBarHidden:YES animated:NO];
    _QFNavigationBar * newNavBar = self.navigationBar;
    [self.view addSubview:newNavBar];
}

- (_QFNavigationBar *)navigationBar
{
    _QFNavigationBar *navigationBar = objc_getAssociatedObject(self, @selector(navigationBar));
    if (!navigationBar) {
        navigationBar =  [[_QFNavigationBar alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 64.0)];
        [navigationBar setItems:@[self.navigationItem]];
        [self setNavigationBar:navigationBar];
    }
    return navigationBar;
}

- (_QFNavigationItem *)navigationItem
{
    _QFNavigationItem * item = objc_getAssociatedObject(self, _cmd);
    if (!item){
        item = [[_QFNavigationItem alloc]init];
        [self setNavigationItem:item];
    }
    return item;
}

代码3:

- (void)setTitle_QF:(NSString *)title
{
    [self setTitle_QF:title];
    self.navigationItem.title = title;
}

从代码2和代码3相信大家也能看出来,我为什么要对这两个函数进行交换,还是解释下代码2是为了保证添加的导航栏在控制器中,视图层级是最高的(ps如果你不乱写),代码3则是为了保证设置控制器标题的时候能够拦截下来,便于显示在我们自定义的导航栏上面.

此外:loadNavigationBar是表示这个控制器是否应该加载导航栏控制器,这个标志会在被push函数中被置为YES,下面是代码

@interface UINavigationController (ExtendNavigation)
@end
@implementation UINavigationController (ExtendNavigation)
+ (void)load
{
    Method originalMethod = class_getInstanceMethod(self, @selector(pushViewController:animated:));
    Method swizzledMethod = class_getInstanceMethod(self, @selector(qf_pushViewController:animated:));
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

- (void)qf_pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    viewController.loadNavigationBar = YES;
    [self qf_pushViewController:viewController animated:animated];
}

ps:_QFNavigationBar是我自定义继承自UINavigationBar的一个类,我们可以在这个类的初始化方法体里面,配置我们导航栏APP主题风格方式,而在_QFNavigationItem,我们可以定制导航栏返回函数,以及按钮图片,下面是具体的代码

#import "_QFNavigationBar.h"

// 缺省情况下导航栏的颜色
#define kDefaultNavigationBar [UIColor whiteColor]
@implementation _QFNavigationBar

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.barTintColor = kDefaultNavigationBar;
    }
    return self;
}
@end
#import "_QFNavigationItem.h"

@implementation _QFNavigationItem
- (void)setViewController:(UIViewController *)viewController
{
    _viewController = viewController;
    if (self.viewController.navigationController.viewControllers.count>1)
    {
        UIImage *backButtonImage = [UIImage imageNamed:@"icon_nav_back"];
        UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithImage:backButtonImage style:UIBarButtonItemStylePlain target:self action:@selector(backTapped:)];
        self.leftBarButtonItem = backBarButtonItem;
    }
}

- (void)backTapped:(id)sender {
    [self.viewController.navigationController popViewControllerAnimated:YES];
}
@end

OK,搞定!一切尽在代码中(原谅我不善表达/(ㄒoㄒ)/~~)
最后附上Demo项目地址:https://github.com/ZYCoderIOS/ExtendNavigation

相关文章

  • iOS界面开发—定制导航栏标题

    上一篇:iOS界面开发—导航控制器和标签控制器当前篇:iOS界面开发—定制导航栏标题 定制规则 在上一篇里,我们提...

  • iOS界面开发—导航控制器和标签控制器

    上一篇:iOS界面开发—开篇当前篇:iOS界面开发—导航控制器和标签控制器下一篇:iOS界面开发—定制导航栏标题 ...

  • UINavigationController

    其他网站的资料:自定义iOS7导航栏背景,标题和返回按钮文字颜色 目录 导航控制器的定制 定制Navigation...

  • swift-导航控制器

    导航控制器作为iOS工程常用的容器类,在定制的时候,需要考虑几个关键点。 1.状态栏风格。 2.导航栏。 3. 右...

  • 定制iOS 7中的导航栏和状态栏(链接)

    iOS 7 教程:定制iOS 7中的导航栏和状态栏

  • 导航控制器

    在Appledelegate.m中将导航控制器设置为根视图控制器,这样APP运行就直接进入导航控制器 导航栏的定制...

  • iOS给控制器定制导航栏

    最近因为项目的需要,需要设计类似与网易一样,每个控制器都能携带一个自己的导航栏,下面就是代码(打字太多,觉得自己都...

  • UINavigationController

    UINavigationController的子控制器 如何修改导航栏的内容 导航栏的注意点 在iOS7之后默认会...

  • iOS15适配

    导航栏 从 iOS 15 开始,UINavigationBar、UIToolbar 和 UITabBar 在控制器...

  • iOS7之后的导航栏与控制器原点坐标问题

    iOS7之后的导航栏与控制器原点坐标问题   简单记录关于iOS7之后有导航控制器的控制器view原点坐标问题(v...

网友评论

    本文标题:iOS给控制器定制导航栏

    本文链接:https://www.haomeiwen.com/subject/eerjxxtx.html