# ios AutoLayout 技术实践

作者: DaZenD | 来源:发表于2018-11-17 11:09 被阅读7次

    前言

    很久没用autolayout,一直用的masonry,再用autolayout,很生疏,写一篇文章,作为手记。

    码字较多,确实令人不想看,希望看到的小伙伴认真读一下.

    Demo

    masonry

    个人比较喜欢标哥关于masonry的见解:博客

    sb,xib

    具体sb,xib的细节这里就不多了解了。下面推荐一篇文章,看下就行了

    iOS进阶—SB和XIB的前世今生

    xib 使用

    xib 原理

    ios开发之xib的详细加载过程

    这篇文章不错,至少之前没有了解到这一点

    xib 转代码

    iOS进阶之xib上控件自动生成纯代码

    这里xib转纯代码,觉得没多大意义,复杂页面转后,会想吐的。不过了解一下也好,初学者,可以将ib视图转为代码,学习控件如何使用的。

    xib 约束

    视图约束,不管masonry还是AutoLayout。深入理解约束一词的意思,万变不离其宗。即把一个视图束缚在一个地方,当页面变化时候,视图不会乱跑。视图变化只有“上下左右”四个维度,仔细理解宽高的变化其实也是上下左右中的变化,所以,怎样束缚一个视图?
    1:确定origin:{x, y}
    2:确定frame:{width, height},或确定右边下边,也相当于确定了宽高。

    所有就会有各种组合:
    上左下右
    上左宽高
    左宽centerY高
    centerXY宽高
    。。。

    autolayout

    关于autolayout的基本了解,这里不多说,推荐简书-一天一点xib系列

    控件集

    viewarea.png

    看这一大片,实际项目中,能用40%就不错了,这篇文章就拣一些常用的了解

    显示区

    displayarea.png

    这里能看到左边是视图层次结构和约束,中间是可视化页面,右边是布局操作区。点点看,没多少东西

    约束操作区

    handlearea.gif

    开发中,常用的也就右下角那几组约束功能。一直用的都是他们

    第一个标签

    Update Frames.单一功能,就是恢复视图原布局的。跟git上的reset、svn的revert差不多,理解成返回就行了

    第二个标签

    Embed In Stack.这是Xcode7在iOS9引入的新功能,它用来统一管理它所有的subView(子视图)上的约束.相当于一个容器view用来统一管理他所有subView的约束,其实普通的UIView也可以作为容器view来管理其subView的约束,我们之前做复杂UI显示逻辑的时候往往也会放一个背景的容器view,stack view就是起到这个作用,意义不是很大,它做的事情UIView也可以做,但是他的优势在于:可以通过设置属性的方式让系统自动添加对其subView的约束,而且该view是不渲染在页面上的,对它设置背景色等属性是无效的...(对android有了解的,这个跟merge差不多)

    第三个标签

    Align.用于添加多个控件间对齐关系,从上到下依次是左对齐、右对齐、上对齐、下对齐、水平对齐、竖直对齐,这些现在都是灰色的不能选择,只有同时选中多个控件,他们才是可用的,或者先选择一个控件,然后按住control拖动到另一个控件上,就会弹出一个控件对齐的窗口,可以在里面设置两个控件的对齐关系。下面两个是相对于superView设置水平、竖直居中,选中单个控件就可以设置

    第四个标签

    Add New Constraints.用于对单个控件设置约束,上面的四个框分别填写上下左右的约束,注意,每个框右侧的三角是可以点击出菜单进行选择的,比如有A、B、C三个控件,A、B同在C的左侧,对C设置左侧约束的时是可以选择针对A还是B进行计算的,如果通过auto layout设置的约束与显示的结果不符的时候,可以点击三角检查是不是设置约束的参照对象选错了。

    Constrain to margins选项的解释:

    当拖动一个控件到另一个控件里时,作为super的控件会有几条参考线(蓝色虚线,如果你使用的硬件是带有Force Touch触控板,且使用的xcode7的时候,拖动到参考线处的时候触控板会轻微震动,发出机械上的一个声音以给你反馈),上下左右四个方向的边缘会有,水平、竖直的中心处会有。

    若勾选Constrain to margins实际super与sub之间的参考边缘就是这些参考线,而不是实际的super的frame的边缘,如果我们不勾选的话就是以frame的边缘为参考。

    下面的Width、Height是限制自身宽高的选项。

    Equal Widths、Equal Heights是与其他控件保持相同的宽高,默认是灰色不可用状态,只有选择两个以上的控件,才可使设置,同样也可以先选中一个控件,按住control拖动,弹出的窗口中也有该选项。Aspect Ratio 是设置自身的宽高比的。

    Align选项同样是设置两个以上控件的对齐关系的。

    Update Frames一般是用来更新frame的。我们设置的约束如果与当前控件的frame产生冲突的时候就要解决冲突,要么修改约束,要么修改frame,最后使系统可以没有歧义的确定UI布局,有冲突的时候会在xib左边栏的右上角显示警告或错误的标识,我们点击标识,按照系统提供的冲突解决方法就可以解决冲突。

    第五个标签

    Resolve autoLayout issue.这个标签主要用于重新设置autolayout.这个标签可以作用在选中的view或者是以这个view为父视图的所有view
    比如:Update Frame,用于更新UI,比如我们设置了自动适应布局,可以用这个选项来更新它的位置.
    Clear Constraint,用于清空所有的约束.

    注意

    如果我们使用了autoLayout自动布局,那么我们在ViewDidLoad和iOS5之后新加入的ViewWillLayoutSubviews中修改Frame均不能生效.这是因为,ViewWillLayoutSubviews这个方法在ViewDidLoad之后调用,也就是说frame生效之后接着就被autoLayout给重新布局了.

    既然这样那么,我们要更改frame就要在ViewDidLayoutSubviews中更改,或者将自动布局拖成属性,在代码中更改.

    属性设置区

    propertysettingarea.gif

    这里面绝大部分设置,用纯代码都能编写。所以,这里设置,转为纯代码,去了解学习控件属性知识也是不错的办法

    第一个标签

    show the file inspector.这个标签主要介绍xib文件的基本信息,一般是不会用到的,所以也不用修改.

    第二个标签

    show quick help inspector.这个标签就是一些快捷帮助信息,基本上就是苹果API中对某个控件的介绍.

    第三个标签

    show the identity inspector.在这个标签下主要做一些标识.我们最常用的就是其中的Custom Class,用这个标签来关联xib文件与我们自己创建的类文件

    第四个标签

    show the attributes inspector.在这个标签使我们最常用的一个标签,我们通常会使用它进行控件的属性设置.比如设置模拟器的一些尺度,颜色等相关的.这个标签的内容(即可设置的属性)会因控件的不同而变化的.

    第五个标签

    show the size inspector.这个标签是设置frame的相关,主要与尺寸相关.

    第六个标签

    show the connections inspector.这个标签主要负责xib文件与类的源文件交互,通俗的将就是"连线",在xib中控件的属性与触发的动作,都是可以拖一条线到类的源文件中,用代码进行下步操作的.这会在接下来进行介绍.

    实践出真知

    下面通过项目中常用的控件约束逐一讲解xib中autolayout的使用

    label

    一般约束

    第一次使用autolayout,先拖一个label试试

    这是xib中autolayout布局的一个label,整个操作如图。

    labeltry.gif

    这是用三方约束库masonry进行约束的,看代码,刚设置的background和text用纯代码写都是一一对应的,所以,这里告诉你,xcode的可视化ui布局做的很棒,开发中一般用到的视图属性设置,这里都能找到设置的地方

    labelmasonry.png

    这是用最古老的纯代码编写ui布局。看下代码量,如果写个稍微复杂点的页面,是不是会觉得不爽。

    labelframe.png

    从上面可以看出,纯代码开发的,就不过多讨论了,比较masonry和autolayout布局。用哪个呢?autolayout能快masonry几条街吧。

    最后,针对刚入门的ios开发来说,建议先masonry,再autolayout。因为autolayout的实现,你并不知道oc代码的具体实现,不利于修炼内功。(当然,外包的话,你是没有那个条件的,只能用autolayout,只为快,只是重复)

    内边距需求

    项目中label一般clear背景展示内容,很少有内景色的,但是如果美工设计需要有内边距的。但是autolayout中并没有内边距设置呀?

    labelattributed.png

    看到label的attributed类型是不是有点联想,我们代码实现label的行间距,字体颜色等富文本设置的时候,用的就是这里的一些东西。但是没有找到能设置内边距的。这种需求可以通过自定义label实现,如下:

    label文本对齐设置内边距

    实践后发现,这种方式内容是显示不全的,这里没有深究,有搞过的朋友,可以留言交流。。。☺

    labeledge.png

    总结:

    uilable 自适应高度,是不带内边距的。如果非要实现上面的方案也有,只是内容显示不全。使用TextView是完美的替代方案。下面会讲textview的用法

    补充

    iOS开发技巧

    如果 nib 或 storyboard 里用了 autoLayout,实际运行顺序是先执行viewDidLoad再执行 autoLayout

    定制边框需求

    视图的边框需求,在项目中大多会用到,我们一般处理方式为view.layer的操作。但是autolayout如何实现呢?

    User Defined Runtime Attritubes:用户定义运行时属性

    bordertool.png

    key path。有些感触吧,oc的kvc编码,所以,对象的属性都可以在这里试试看。只是有些特例无法直接实现,如boder.color。。

    注意: runtime,看到了吧,所以,xib中是无法可视化的。运行起来才能看到效果。

    特例:设置边框颜色

    layer.borderColor type里只有Color 没有CGColor。

    解决:CALayer分类 提供方法:transeColor2CGColor:(UIColor *)color。方法写不写在.h里面都无所谓

    使用:layer.transeColor2CGColor

    注意:正常来讲,分类里是没有属性的,但是在使用时候,就当有属性使用,所以,方法名一般为setAbc。然后xib中设置时候使用是abc,如下:

    CALayer+Color.png layerbordercolor.png

    实际操作时候,尽量还是用copy,手敲的话,很容易手误,又很难发现。如果设置错误,系统默认为黑色。

    textview

    高度自适应需求

    针对label,textview等需要根据文本内容,高度自适应,可以使用纯代码计算内容高度,但是大家应该也比较诟病这种方法,诸如开发麻烦,计算不准等。使用autolayout相对来说有种方案就简单多了,如下:

    textviewadjustheight.gif

    看效果:

    label2textview.png

    这里有两点注意:

    1:设置过后,看上图,高度约束变虚线了。
    2:用过masonry都知道,每条约束都有优先级,因为masonry也是封装的NALyoutConstraint嘛,看下图,不解释。

    constraintpriority.png masonrypriority.png

    总结:
    在内容自适应高度的布局需求中,这种布局方式也是一大利器。请善用

    1:有内边距

    2:内容默认吸顶

    3:如果需要自适应高度,调整高度自适应,不让滚动即可实现

    需求拓展

    在实际开发中,textview不能一直随着内容增高,会有一个最大高度。实际开发中,我们一般使用封装好的自定义textview。如下,这里讲autolayout,不过多的了解如何自定义

    自定义textview

    iOS 使用UITextView计算高度,一行代码搞定

    button

    通过上面label的练习,大部分单个视图的约束操作都是能应对的。下面以button为实例,了解一下不同状态的练习。

    button 基本设置:背景色、背景图片、图片、标题、圆角、状态:正常,高亮,选中,等

    推荐好文

    多操作,熟能生巧,xib中ui布局都是操作性的

    imageview

    imageview基本操作这里就略了,跟上面一样,下面说一些进阶的:

    imageview添加子视图

    没有实际操作过的,并不觉得这里有什么,坑点就是imageview上没法添加子视图。纯代码你也可以实践试试。下面说下xib如何实现:

    superimageview.png

    imageview 添加子视图:拖拽uiview视图,class 改为imageview,由于是UIView,要在.m中设置图片

    总结:
    碰到视图嵌套的需求,如果父视图不支持嵌套,可以试试这么干。把UIView转为对应子类型

    tableview

    终于说到tableview,初入门ios的,感觉tableview有些懵逼吧,什么协议,代理,数据源等一些新名词,整的费解。不过,这里说的是布局,嘿嘿

    展示全部内容

    tableview本身是可以滚动的,如果cell不多,想展示全部内容共,让tableview根据cell自适应高度。参考下面collectionview部分。demo中有实现。

    cell自适应高度

    我们实际开发中共,cell自适应高度一般使用的都是三方库:

    xib布局对应:UITableView-FDTemplateLayoutCell

    masonry布局对应:HYBMasonryAutoCellHeight

    推荐标哥相关masonry笔记

    这里了解一下,不用三方库,实现cell自适应高度的操作:self-sizing cell,实在不想码字了,看demo实践

    推荐好文

    collectionview

    如何显示collectionview全部内容这里有个论题,可以看看。实践发现,方案如下:

    方案:
    collectionView的contentSize.height赋给collectionView的高度约束。

    总结:
    collectionview作为复杂页面的子视图,如果需要展示全部cell,这种方案是比较好的。tableview也同样道理。如果有需求,就可以这么干。。

    1:设置collectionview不可滚动
    2:设置collectionview高度约束

    注意:获取contentSize一定要在cell加载完成后,不然获取到为0。collectionview是不会显示的,cell也不会加载。

    scrollview

    开发中,有些页面,无规律没法用tableview,但是有很长,超过了屏幕,我们首选scrollview。说到scrollview,感觉是比较难用的,特别是masonry布局时候,有些麻烦。这里了解一下,提供一个不错的方案。

    scrollview约束

    因为scrollview是可以滚动的,所以有个自身的frame,还有个并不存在的contentview,就是scrollview里的子视图们。想象一下放映机,放映口和胶片。放映口相当于scrollview的frame,胶片相当于scrollview内的内容。一旦胶片长度超过放映口。是不是就有滑动的观感了。tableview和collectionview和textview都是继承自scrollview,所以,都是同样的道理。如何实现?原理就是scrollview添加containerview。子视图们撑开containerview,将constainerview的size作为scrollview的contentsize。

    目的:确定 scrollview 的 contentSize

    三步:

    1:添加scrollview,并约束

    2:添加containerview,并约束

    scrollviewconstraint.gif

    理想情况这里应该正常的啊,然而,看一下约束错误。表示scrollview没法确定x方向的position或width,和y方向的position或height。

    3:约束解决

    我们目的是确定scrollview的contentsize。那么即是确定containerview的size{width,height}和origin{x,y}。如下:
    1):width。同scrollview的frame的width即可。已经约束过
    2):xposition/width。假设需求是竖直滚动。那么设置水平居中是最合理的。因为scrollview中content的左右相对约束点你都不知道。containerview的左右相对scrollview已经约束过,怎样组合,水平方向才能束缚住containerview不乱跑呢?一是设置containerview的width,二是水平居中,试试看:

    scrollviewconstraintsolvehor.gif

    3):yposition/height。由于需求是竖直滚动,所以,不能竖直居中,只能约束containerview的height。

    scrollviewconstraintsolvevertical.gif

    scrollview滑动

    以上scrollview的约束做过了。知道原理,scrollview以什么样的frame存在或嵌套都是可以应对的。西面了解下开发中常见的场景:

    subviews超过一屏,使用scrollview实现滚动:

    方案:手动计算更新containerview的height约束。

    这种虚拟器窗口不能变动


    simulatedmetricsinferred.png

    调整metrix


    simulatedmetricsfreeform.png

    调整虚拟窗口,拉大高度


    simulatedmetricsscroll.png

    手动计算-动态设置containerview的高度

    handlecontainerviewheight.png

    控件平分

    上面了解了单个视图的布局。下面了解一下多视图组合布局的技能。

    需求:视图等宽等间距平分父视图

    viewdivide.gif

    比例布局

    实际开发中,比例布局用的感觉不是很多。这里也了解一下:

    multiplier.gif aspectratio.gif

    这个第二类约束,解释一下:

    约束过红view的宽高ratio后,约束报错,是因为已经约束了宽高,现在又约束宽高比1:2,跟原宽高比不一样,所以,删除宽高的任一约束即可。

    组合批量处理

    先看个错误的栗子。

    grouphandleerror.gif

    green的view为啥跑到前面去了呢?而不是4个view左右平分。看下green视图的相对约束,发现是相对于safe area。为啥呢 ?因为干刚开始放的时候,green视图就非常靠上,该视图左右能看到的第一个视图就是safe area。所以,就这样了。这也是autolayout方便的一点,默认视图依赖,下面看正确的处理。。

    grouphandle.gif

    解释一下:组合批量处理分3个步骤:

    1:预先处理

    上面错误例子演示了,首先要把几个视图放到差不多的位置,然后再进行整体处理

    2:划整体处理

    将视图组处理为一个整体:

    1:水平对齐
    2:左右平分,等宽等高

    3:整体约束

    上面将视图化为一个整体了,剩下的,就单选任一个视图,确定yposition/height即可。这里操作的是blue视图,topSpace和height。这样就确定了每个视图的上下左右或宽高四个约束了

    组合自适应布局

    这种布局的场景一时没想起来,没遇到过。这里就不多了解了。推荐一篇好文:

    好文推荐

    子视图撑开父视图

    这类布局需求太常见了,总想有骚操作来实现,实际开发中总是用笨方法,计算子视图高,更新父视图高。这一点都不智能啊:用autolayout下面有一种方法,一起了解一下:

    groupadjust.gif

    解释:

    高度自适应

    设置约束,记住规则:先父后子,父无高需自适,子一一约束四方,最后父依赖最底视图的底部。

    图中的子视图,由于自适应内容,所以特殊设置了高,priority。上面label,textview有了解过。

    priority设置多大?

    系统提供的有Required:1000,High:750,Low:250。这里设置时候取值范围:0 < x < 750 & x != 250。

    看效果:

    groupadjustresult.gif

    基于Object封装

    推荐文章。。这里有了解object的使用。我也是照着实践的,所以,就不搬砖了

    基于UIView封装

    基于UIView封装xib: xib 还没那么强大:

    1:如果想实现vc.xib自动初始化customview。那么,vc和view就没法共用view中的交互

    封装自定义view步骤
    1):customview.xib不设置同名class
    2):customview.xib设置file's owner为同名cutomview类
    3):在vc.xib直接使用view视图,设置class为customview即可
    

    2:如果想实现vc和customview共用customview中的交互。那么,vc中需要手动加载customview.xib。并约束。

    封装自定义view步骤
    1):customview.xib设置同名class
    2):customview.xib设置file's owner为所在vc类
    3):在vc中加载customview.xib。按需约束。
    

    1):约束不能和vc.xib统一约束,可以masonry和autolayout共同约束,所以,一般可用在单一约束上,没有其他customview的相对约束,比如:tableview的headerview。

    2):customview.xib不能放到customview中initwithcoder进行初始化加载。只能使用的地方手动加载。因为:customview.xib的file's owner是vc

    没有图示,是不是看的云里雾里的。真正实践过的,应该知道我在说什么。看到这里的有兴趣的朋友,一起交流。

    xib 高深用法

    推荐好文

    这里详细讲解了xib一些高端用法,个人了解较少,就不乱说了

    总结

    一起了解了autolayout的一些基本和进阶用法,autolayout操作都是技能性的,多练习就ok了。这里不能穷举所有的用法,学会自己摸索,根据约束错误提示,练习自己的约束方案和习惯

    相关文章

      网友评论

        本文标题:# ios AutoLayout 技术实践

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