美文网首页Work
阅读LTNavigationBar有感

阅读LTNavigationBar有感

作者: 李昭宏 | 来源:发表于2017-04-07 16:38 被阅读303次

    最近,在公司做登录界面,需要用到导航栏隐藏,虽然很快就实现了功能,但是想起来,一些比较酷炫的UI效果,所以决定学习一下关于LTNavigationBar的源码

    代码规范

    之前看Effective Objective-C 52个高效法则的时候,就已经学会了,通过用户关联来让category中含有属性对象,从而实现各种需求上的拓展,这次再看LTNavigationBar的时候,发现了更加方便的写法,以往还需要在.h文件书写属性,然后在.m文件通过get和set方法来对象关联

    navigationBar透明度变化效果navigationBar透明度变化效果 navigationBar的y坐标变化效果navigationBar的y坐标变化效果
    //UINavigationBar+Awesome.h
    
    #import <UIKit/UIKit.h>
    
    @interface UINavigationBar (Awesome)
    - (void)lt_setBackgroundColor:(UIColor *)backgroundColor;
    - (void)lt_setElementsAlpha:(CGFloat)alpha;
    - (void)lt_setTranslationY:(CGFloat)translationY;
    - (void)lt_reset;
    @end
    

    作者在.h文件中没有设置属性,而是在.m文件直接对象关联.

    首先了解UINavigationBar的subview有哪些东西

    (lldb) po [self.navigationController.navigationBar subviews]
    <__NSArrayM 0x60000005a010>(
    <_UIBarBackground: 0x7fcabdd0ab30; frame = (0 -20; 375 64); userInteractionEnabled = NO; layer = <CALayer: 0x608000237200>>,
    <_UINavigationBarBackIndicatorView: 0x7fcabdc22dc0; frame = (8 11.5; 13 21); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6000000376e0>>
    )
    

    核心代码

    //UINavigationBar+Awesome.m
    
    #import "UINavigationBar+Awesome.h"
    #import <objc/runtime.h>
    
    #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
    
    @implementation UINavigationBar (Awesome)
    static char overlayKey;
    
    //直接getter和setter方法,不需要加上属性,也可以对象关联,从而外部无法得出内部技术实现,只需要调用函数方法即可
    - (UIView *)overlay
    {
        return objc_getAssociatedObject(self, &overlayKey);
    }
    
    - (void)setOverlay:(UIView *)overlay
    {
        objc_setAssociatedObject(self, &overlayKey, overlay, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    //设置背景颜色
    - (void)lt_setBackgroundColor:(UIColor *)backgroundColor
    {
        if (!self.overlay) {
            //直接把NavigationBar背部的图片替换,使用[UIImage new]来替换
            [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
            //初始化控件,设置frame
            self.overlay = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + 20)];
            //取消传递事件
            self.overlay.userInteractionEnabled = NO;
            //设置自身autoresizing模式,不然会不能撑满全屏的宽度
            self.overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth;    // Should not set `UIViewAutoresizingFlexibleHeight`
            //遍历UINavigationBar的subview可以发现有3个子控件,第一个就是_UIBarBackground,既是在我们核心需要替换的时候,将自身绑定的view覆盖在这上方,从而实现透明的视觉效果
            [[self.subviews firstObject] insertSubview:self.overlay atIndex:0];
        }
        //设置关联的view的背景颜色
        self.overlay.backgroundColor = backgroundColor;
    }
    
    - (void)lt_setTranslationY:(CGFloat)translationY
    {
        self.transform = CGAffineTransformMakeTranslation(0, translationY);
    }
    
    - (void)lt_setElementsAlpha:(CGFloat)alpha
    {
        //左边的导航栏的子控件
        [[self valueForKey:@"_leftViews"] enumerateObjectsUsingBlock:^(UIView *view, NSUInteger i, BOOL *stop) {
            view.alpha = alpha;
        }];
        
        //右边的导航栏的子控件
        [[self valueForKey:@"_rightViews"] enumerateObjectsUsingBlock:^(UIView *view, NSUInteger i, BOOL *stop) {
            view.alpha = alpha;
        }];
        
        //导航栏的标题栏的子控件
        UIView *titleView = [self valueForKey:@"_titleView"];
        titleView.alpha = alpha;
    //    when viewController first load, the titleView maybe nil
        //遍历自身的子控件,从上面可以看到_UIBarBackground,_UINavigationBarBackIndicatorView,核心让这些透明度发生变化即可
        [[self subviews] enumerateObjectsUsingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
            if ([obj isKindOfClass:NSClassFromString(@"UINavigationItemView")]) {
                obj.alpha = alpha;
            }
            if ([obj isKindOfClass:NSClassFromString(@"_UINavigationBarBackIndicatorView")]) {
                obj.alpha = alpha;
            }
        }];
    }
    
    //重新设置回原来,并且将自身绑定的view更新好
    - (void)lt_reset
    {
        [self setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
        [self.overlay removeFromSuperview];
        self.overlay = nil;
    }
    
    @end
    

    总结

    虽然难度不大,但是学到了对象关联的更好的写法,并且进一步了解了UINavigationBar的处理,虽然代码量不大,但是对大部分开发者都有很多帮助,希望可以更好提升我们自己的代码质量,写出更多高质量的代码~

    相关文章

      网友评论

      • YxYYxY:请问一下使用这个库的时候,push进去然后pop回来的时候,并不是像图中那样,而是会有个闪动:cold_sweat:
        李昭宏:@YxYYxY 我今晚测试一下~ 微信huagonglzh
        YxYYxY:@昭宏李哈哈哈 你好,我测试了好久,依旧有闪动这个问题!可以给个联系方式请教一下吗?
        李昭宏:那个是因为NavigationBarHidden的那个属性,你可以试一下,在push进去的界面和pop回来的界面的viewWillAppear修改一下NavigationBarHidden的那个属性

      本文标题:阅读LTNavigationBar有感

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