美文网首页iOS小记iOS开发专区ios基础知识
关于如何写UI及屏幕适配的一些技巧(上)

关于如何写UI及屏幕适配的一些技巧(上)

作者: CoderLXWang | 来源:发表于2016-11-23 22:28 被阅读3583次

    因为公司开启了一个新的iOS项目, 所以近期比较忙, 没有更新博客,今天打算总结一下关于UI布局及屏幕适配的一些实战技巧,尤其使用纯代码,会对提升效率及代码易于维护等方面有明显帮助,这里提到的没有使用任何Xib, 如果不是在外包公司,也推荐大家多使用甚至完全使用纯代码布局UI,优缺点下面会说明,本文布局使用masonry。货不太干,只是工作中的一点点小技巧与基础知识,大家可以来分享更多的技巧。

    下篇地址:http://www.jianshu.com/p/0c1d76e7ea1a

    提纲:
    1. 关于xib/storyboard 与 纯代码的对比  
    2. 一条规范(又提了一点关于命名的)
    3. UI工厂类 与 代码块
    4. 懒加载, View使用strong还是weak
    5. 复杂界面要会分区,要会障眼法
    6. masonry均布View,及其布局时约束依赖关系
    7. 关于屏幕适配的一点技巧
    
    1. 关于xib/storyboard 与 纯代码的对比

    a. xib快,纯代码慢,但是在纯代码熟练的情况下, 并不会慢很多
    b. xib不易于修改,怎么修改,就是今天让一个View上的元素这么排布,明天就要换种排布方式,后天又要加些东西。。。
    c. xib不灵活,什么叫灵活,一个View上有10个元素, 其中5个都是不一定出现的,并且它们不是集中的布局在哪个位置, 乱七八糟的,多一个少一个布局还都有点影响,这就知道灵活的重要性了
    d. xib不利于屏幕适配,怎么适配,5s上一个View距左10像素,产品说6p上就要距左20才协调,xib上拖线布局怎么搞,约束拖出来改变它吗,复杂View有10个需要这样处理的地方呢。。。
    e. xib写多了纯代码手生,当然纯代码写多了,拖线也有点不熟练,这个不作为纯代码更好的原因。。。
    f. 但是!面试的时候如果你说我xib用的多,纯代码布局有点不熟练, 不好意思, 拜拜(本人经历过),你说我都是纯代码布局的, xib会,不熟,大多公司听到以前都是纯代码,那没问题,因为他们公司也不用xib。。。

    2. 一条规范(又提了一点关于命名的)

    “ .h 和 .m 的类扩展里面不要随便加东西,尤其 .h 里的东西一定要是必须放在这里,放在别处不行,实在有不太重要还必须放在这的,打好注释 ”

    这个东西无数次在项目中见到过随意在这加东西的做法, 刚写完当时还好, 一个月以后再看, 瞬间懵逼。。。
    这是什么鬼。。。
    当时为啥要写这个量。。。
    这怎么还有个没用过的量。。。
    这个东西要不要传, 为啥A类用的时候穿了, B类就不传了。。。

    再提一下另外一个规范, “名字不要随便起,弄个坑爹名字,自己隔天都不知道啥意思,是跟公司结了仇了还是怕泄露天机”

    不算特别不规范的命名

    为什么说这些命名不是特别不规范, 因为这里面虽然有些vBack啦, lbl啦, tbl啦, 不是那么容易理解, 但是好歹是lbl,都用lbl了,不过为啥非得把Label放前面,官方命名的时候比如btn.titleLabel,Label也是放在后面的啊, 也没缩写成什么lbl,我们就简简单单的叫nickNameLabel不行吗。。。

    说到命名就再多说一点, 如果一个复杂View内部布局的时候需要分割成几部分,在能想出名字的情况下最好不要按位置命名,比如topView,midView之类,明天产品说把位置调一下,最下面的部分比较重要提到最上面,这怎么办, 尽量想一想这部分大概负责什么,要表达个什么意思

    3. UI工厂类 与 代码块

    UI工厂类: 其实代码很简单,就是把对Label, Button等控件的属性赋值封装一下, 做到一行代码就能创建一个VIew, 如下图, 虽然这一句代码有点长, 但是习惯之后写个View是真心快

    UI工厂类.h UI工厂类.m

    代码块: 代码块就是下图的东西, 应该没人不知道,不会添加隔壁百度

    代码块

    这个东西不光是UI布局用, 很多位置都比较方便, 我常用的有这样几个

    懒加载 masonry定义过的一部分 masonry填空模式

    尤其是纯代码masonry布局, 这样的代码块会让你布局的速度直逼甚至超越拖线, 只需要打出make就会出现已经定义好的各种约束, 比如要布局高度, 打出makeh, 回车, 就直接进入填空模式,tab切换填空即可

    4. 懒加载, View使用strong还是weak

    为什么要用懒加载, 有一种说法是用到的时候在创建,节省内存开销,这种说法固然没问题,但是对于大部分UI来说,基本迟早都会被创建。
    所以,主要优点不在这里,本着<自己的事情自己做, 尽量不要影响他人>的做人原则,代码也该这样写,你既然是个View,那你就把自己解决好再来见我, 我要用你的时候只需要self.testView就可以了,下面两张图对比一下就会看到区别了,第二张为刚到公司时上一任的大作,这里选取了一种比较看的清的贴出来

    弱引用懒加载 masonry布局

    上图注意:masonry的block没有进行copy,即当前对象没有引用这个block,是局部的引用,不会形成循环引用的,可以不用weakSelf

    混乱的还好的示例

    对比一下即可看出来, 由于上图使用中的控件均使用懒加载, 所以布局方法里连addSubView都不用写了, 只需逐条布局即可, 下图中创建控件, 属性赋值, 添加到父视图的代码都混在一起, 并且还没有使用masonry, 用上之后只会更乱。。。

    ** View使用strong还是weak:** 关于这个问题,其实还是有很多可以说一下的地方
    懒加载写法:

    
    @interface ViewController ()
    
    @property (nonatomic, weak) UIView *weakView;
    @property (nonatomic, strong) UIView *strongView;
    
    @end
    
    @implementation ViewController
    
    /** 
     UI控件使用弱引用创建方法
     1. UIView *weakView = [[UIView alloc] init]; 这句必须声明一个局部变量, 不能用_weakView,
        因为用 _weakView = [[UIView alloc] init], 等号右侧创建了一个View之后,给了一个弱引用持有,相当于没有持有,直接就释放掉了
        而 UIView *weakView = [[UIView alloc] init],等号左侧的weakView默认是一个强引用,会暂时持有保住它,但是生命周期就在这个懒加载的大括号内,所有会有其他代码配合, 使这个View存活下来, 不被释放
     
     2. _weakView = weakView; 这句代码为属性赋值, 以后在其他位置不管通过self.weakView还是_weakView才能找到这个View,
        基本作用可以说等同于强引用的 _strongView = [[UIView alloc] init];
     
     3. [self.view addSubview:weakView], 第一条注释中说了,UIView *weakView 的生命周期就是在这个{}内,那么如何保证出了括号依旧存在,就是要给这个View加到一个不会被释放的View(不一定强引用弱引用)上,即self.view, 这样就不会被释放掉了
     */
    - (UIView *)weakView {
        if (!_weakView) {
            UIView *weakView = [[UIView alloc] init];
            _weakView = weakView;
            
            weakView.backgroundColor = [UIColor redColor];
            
            [self.view addSubview:weakView];
        }
        return _weakView;
    }
    
    - (UIView *)strongView {
        if (!_strongView) {
            _strongView = [[UIView alloc] init];
            _strongView.backgroundColor = [UIColor greenColor];
        }
        return _strongView;
    }
    

    布局时区别:

    - (void)configView {
        
        WeakSelf(ws);
        
        //弱引用由于懒加载直接加到父视图上,所以点语法完了直接调用masonry布局方法即可
        [self.weakView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.equalTo(ws.view);
            make.top.equalTo(ws.view).offset(100);
            make.size.mas_equalTo(CGSizeMake(100, 100));
        }];
        
        [self.view addSubview:self.strongView];
        [self.strongView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.equalTo(ws.view);
            make.bottom.equalTo(ws.view).offset(-100);
            make.size.mas_equalTo(CGSizeMake(100, 100));
        }];
    }
    
    

    移除之后的区别(重点,涉及到理解强弱指针):执行上述代码后,屏幕上出现一上一下两个View, 点击空白区域, 移除掉两个View, 1秒后看一下,1秒后看是因为, 出了这个方法, 也就是运行到结束的括号之后, 才会把View移除掉, 注意看坐下控制台两个View,weakView为nil, 即已被释放, strongView还是存在, 因为即使从父视图上移除, self本身对其还有一个强引用, 不会释放掉,那么如果想把这个View释放掉需要怎么办, 就是在[_strongView removeFromSuperview]后面加一句_strongView = nil;

    注意weakView为nil,strongView还存在 强指针View置空

    下面图解一下, 为什么不置空, strongView就不被释放

    强弱指针View实际区别

    总结起来的话, 其实如果理解到位,使用强弱都没有问题,但是一般来说,由于弱引用会被及时的释放掉,同时,weak在对象消失后自动把指针变成nil。所以需求允许的话,一般建议使用弱引用,那什么情况不能使用弱引用呢,这个要看具体需求,举个例子,如果一个View,需要从父View移除掉,但是之后还有可能加回来,还要保持移除之前的样子,这种情况强引用会更适合。


    收集了一些意见:

    1. 懒加载不一定一定要, 这是完全没问题的,有人习惯把创建View,属性赋值,添加到父视图的代码写在一起,认为这样便于管理,顺着看更清晰,没问题。
    2. 如果View层次复杂,用懒加载弱引用View的时候注意层级关系,如果理解不到位,容易产生问题,因为addSubView写在懒加载里,极易造成层次不清晰,这时就要个人理解,用自己认为最适合的方法了。
    3. 我为什么喜欢将UI写成懒加载?aView就是aView,bLabel就是bLabel,每个控件做好自己事情,给自己颜色字号都弄好了,等我要用你的时候,比如要往父视图添加了,拿来直接加就好,所以在添加View这个方法里都是添加,无关代码没有,要修改aView背景色,去找aView(aView的懒加载里面改)啊

    本篇暂时先写到这里,后面的这两天会发出来,感觉有帮助的话可以关注一下,点个赞,码字不易,共同进步。

    相关文章

      网友评论

      • 知了此生:控件用方法来定义简直不要太好
      • 毛豆家的老疙瘩:我也是纯代码,公司上一个项目用sb写的,真的跟蜘蛛网一样,太乱了,我去了之后,直接重构了,看着太闹心了 ,sb或者xib平时写写demo,偶尔会用,但是项目中,一定是纯代码:joy::joy:
        CoderLXWang: @毛豆家的老疙瘩 🍻
      • ekg:xib动态调整布局这块是有点蛋疼,要把布局引来控制
        CoderLXWang:@ekg 正解,多了完全弄不了
      • f680dfb8c555:懒加载那块跟作者观点完全一样
      • 49043a795ae0:感谢分享!
        CoderLXWang:@future_so ✌
      • 懒猫的鱼:写得挺好 ,思路清晰,文字易理解。反正我招人尽量不招啥都喜欢 用 xib的,固然是快,但需求一修改,就知道 xib和纯代码的区别了:smile:
        懒猫的鱼:@yangzhuxiao 那你试没试过,在你说的条件下,使用xib适配所有屏幕,包括iPad。:relieved:
        3da1492bab3f:需求改动大的话,比如新添加、移除一些控件,用代码一样的会费很多时间。而且页面复杂,控件非常多的话,纯代码改起来反而可能更慢
        CoderLXWang:@懒猫的鱼 谢谢
      • Bearger:受教了~!
        关于xib/sb还是纯代码争议好大样子,然而,我这边的情况很简单,整个项目团队不让用xib/sb。so, :joy:
        1995Oneself:@Bearger 哈哈哈
        CoderLXWang:@Bearger 我就说,不让用的公司多啊。。。
      • 壮了个壮:额...在iOS大全公众号里看到楼主文章专门跑过来过来和楼主理论楼主对xib的偏见,发现原来我来晚了...个人也站在能使用xib就不是用代码的一边,但看到那么多人提出了xib的优势,就想着反过来举几个确实xib不好的地方...
        1.xib在团队协作上不方便,xib是xml文件,团队协作的时候如果同时修改一个xib文件就会产生xml文件冲突,不知道怎么merge,毕竟xml语法不是每个人都懂。
        2.xib和storyboard在初始化上需要注意很多生命周期的问题,如对象是否初始化。在供其他人调用的时候也相对不方便,需要多倒入一个xib文件。
        3.xib和storyboard本身存在一些极端情况下的未知的问题,不好查找。本人就曾经在制作导航栏的时候遇到过下面奇葩情况,tabbar a推出一个由xib初始化的tabbar b,并且在b推出时隐藏a的导航栏,并对b的导航栏做一个背景图片的设置,会出现b导航栏有0.988...透明度的问题,改成代码初始化完全没问题
        最后想说,各有优劣,但推荐能使用xib就不是用代码布局,时间就是金钱
        CoderLXWang:@壮了个壮 不过还是感谢你写了这么多,用心了
        CoderLXWang:@壮了个壮 时间是金钱,但是可维护性更贵啊
      • Sanchain:sb,xib,masonry 都有用到 各有优势。这个工厂类:+1:🏻
        Sanchain:@CoderLXWang 是的:smile:
        CoderLXWang:@Sanchain 工厂类这种东西就看自己需求,搞搞自己常用的就好
      • 2dffecac3330:楼主偏见了,代码和xib结合使用吧,一些固定样式的东西没必要写代码浪费时间。storyboard基本没用过。
        nenhall:@CoderLXWang cell,一些子视图可以用,其它我也不太喜欢
        CoderLXWang: @Coder_Wayne1 适配不好弄,修改样式了不好弄
      • fly大梦想家:挺干:blush:🌹,细节很重要嘛
      • 6a6db38116bc:xib适合不怎么改变的静态页面比较好,我比较喜欢用纯代码。
      • HQFlying:等着下篇呢哈 :smile:
        CoderLXWang:@HQdone 正在写呢,差不多完成一半了,上篇收集了一些问题,一起说一下
      • c9ebc29b0e64:楼主偏见有点大,熟练地纯代码选手要跟熟练地 xib/sb 选手比较,精通了你才知道他的优势,快的不是一点点,连布局代码都手生的选手不值得要。不知道曾经那些喷 ARC 的大神是否还在用 MRC,苹果推荐他是有他的理由的,等过两年再看。
        c9ebc29b0e64:@CoderLXWang 代码是基础,我只认同灵活性的优势,需要灵活地时候自然会用代码,或者结合着用,多数还是追求效率。
        CoderLXWang: @吖吖_吖吖 至于我举得例子,只是做了个极端对比,假设一定不能精通两种的时候,公司非要一个,基本没悬念
        CoderLXWang: @吖吖_吖吖 本人一年半xib,后来一年纯代码,xib是快不假,但是除了快体会到了纯代码布局的更多优点,至于如果真有的人都精通除了快,还是喜欢xib,那就是个人喜好问题了,青菜萝卜各有所爱了
      • Hardway:小学生
        CoderLXWang: @Hardway 都是小学生
      • Yeeshe:楼主有点偏见了,xib或sb没有那么low,主要看精通不。第一个,比例适配完全没有问题,主要找好参考系,然后利善用约束的multipliter可以到达要求,并且如果只适配8.0以上,cell动态高度两句话搞定!多个视图的话可以利用约束的优先级实现,只是代码会比较繁琐,但用纯代码也不简单。整体而言,是一个仁者见仁的事情,代码的灵活加上可视化的直观才会是普遍项目的正解,不加班,高效率,低冗余!
        CoderLXWang: @1454123008 他说的一句是设置自动高度,一句是设置预设高度,其他内部靠约束撑满,手写也是要设置这两句
        64fb2e84de0b:@yxiang 兄弟 两行代码? 请教一下哦
        CoderLXWang: @yxiang 偏见我承认是有的,但是大多公司也是不允许使用,所以还是作为辅助好点
      • 郑一一一一:好用心啊,这样的文章 对于我这样刚入门半年的来说,简直不能再干,解决了我许多在开发的困惑。谢谢!只是对masonry 的block没有进行copy,那一段不太理解意思,现在对block 的浅显理解是 block会造成循环引用。。希望能得到解答
        CoderLXWang: @啊啦哈 差不多,源码之前看过忘记了,应该说这个view没有强引用这个block好像更恰当一点,因为这个block就是为view才弄出来的
        郑一一一一:@CoderLXWang 哦,谢谢,我大概懂了,因为视图控制器没有强引用这个block,所以就没有循环引用么?
        CoderLXWang: @啊啦哈 谢谢支持啊,有帮助就好,这几天我会写完下篇,关于循环引用以及masonry是否循环引用,下篇再详细说一下,先简单说一下,假设给某个布局的block取名ablock,没有进行copy,实际上就是指这个ablock不是self的,即不能self.ablock,不持有,即不能构成循环,至于到底何为循环引用,后面说吧
      • zhouhao_180:学到了 :+1:
        CoderLXWang: @周浩zz 🍻
      • dslCoding:关注楼主
        CoderLXWang:@dongshilei :beers:
      • o0下一站生活0o:楼主在那个公司啊?
        CoderLXWang: @o0下一站生活0o 上海一家小型的创业公司

      本文标题:关于如何写UI及屏幕适配的一些技巧(上)

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