美文网首页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给控制器定制导航栏

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