Auto Layout前世今生

Auto Layout ,是苹果公司提供的一个基于约束布局,动态计算视图大小和位置的库,并且已经集成到了 Xcode 开发环境里。

在引入 Auto Layout 这种自动布局方式之前,iOS 开发都是采用手动布局的方式。而手动布局的方式,原始落后、界面开发维护效率低,对从事过前端开发的人来说更是难以适应。所以,苹果需要提供更好的界面引擎来提升开发者的体验,Auto Layout 随之出现。但是在推出来之后,响应却平平,其原因就在于对其性能的担忧。即使后来,苹果公司推出了在 Auto Layout 基础上模仿前端 Flexbox 布局思路的 UIStackView 工具,提高了开发体验和效率,也无法解除开发者们对其性能的顾虑。

iOS 12 将大幅提高 Auto Layout 性能,使滑动达到满帧。这不得不说Cassowary 算法。

Cassowary布局算法

Cassowary 能够有效解析线性等式系统和线性不等式系统,用来表示用户界面中那些相等关系和不等关系。基于此,Cassowary 开发了一种规则系统,通过约束来描视图间的关系。约束就是规则,这个规则能够表示出一个视图相对于另一个视图的位置。由于 Cassowary 算法让视图位置可以按照一种简单的布局思路来写,这些简单的相对位置描述可以在运行时动态地计算出视图具体的位置。视图位置的写法简化了,界面相关代码也就更易于维于维护。苹果公司也是看重了这一点,将其引入到了自己的系统中。由于 Cassowary 算法本身的先进性,更多的开发者将Cassowary 运用到了各个开发语言中,比如 JavaScript、.NET、Java、Smalltalk、C++都有对应的库。

Auto Layout 的生命周期

Auto Layout 不只有布局算法 Cassowary,还包含了布局在运行时的生命周期等一整套布局引擎系统,用来统一管理布局的创建、更新和销毁。了解 Auto Layout 的生命周期,是理解它的性能相关话题的基础。

这一整套布局引擎系统叫作 Layout Engine ,是 Auto Layout 的核心,主导着整个界面布局。

每个视图在得到自己的布局之前,Layout Engine 会会将视图、约束、优先级、固定大小通过计算转换成最终的大小和位置。在 Layout Engine 里,每当约束发生变化,就会触发 Deffered Layout Pass,完成后进入监听约束变化的状态。当再次监听到约束变化,即进入下一轮循环中。整个过程如下图所示:

图1:Layout Engine 界面布局过程

图中, Constraints Change 表示的就是约束变化,添加、删除视图时会触发约束变化。Activating 或 Deactivating,设置 Constant 或 Priority 时也会触发约束变化。Layout Engine 在碰到约束变化后会重新计算布局,获取到布局后调用 superview.setNeedsLayout(),然后进入 Deferred Layout Pass。

Deferred Layout Pass 的主要作用是做容错错处理。如果有些视图在更新约束时没有确定或缺失布局声明的话,会先在这里做容错处理。

接下来,Layout Engine 会从上到下调用layoutSubviews() ,通过 Cassowary算法计算各个子视图的位置,算出来后将子视图的 frame 从Layout Engine 里拷贝出来。

在这之后的处理,就和手写布局的绘制、渲染过程一样了。所以,使用 Auto Layout 和手写布局的区别,就是多了布局上的这个计算过程。

Auto Layout 性能问题

Auto Layout 在 iOS 12 中优化后,它的性能得到了极大的提升,已经基本和手写布局一样可以达到性能随着视图嵌套的数量呈线性增长了。而在此之前的 Auto Layout,视图嵌套的数量对对性能的影响是呈指数级增长的。使用 Auto Layout 一定要注意多使用 Compression Resistance Priority 和 Hugging Priority,利用优先级的设置,让布局更加灵活,代码更少,更易于维护。

图2: Auto Layout 在 iOS 12 中优化后的表现

AutoLayout常见的问题

(1)几个更新方法的区别

  • setNeedsLayout:告知页面需要更新,但是不会立刻开始更新。执行后会立刻调用layoutSubviews。
  • layoutIfNeeded:如果有需要刷新的标记,立即调用layoutSubviews进行布局;如果没有标记,不会调用layoutSubviews。如果希望立刻生成新的frame需要调用此方法,利用这点一般布局动画可以在更新布局后直接使用这个方法让动画生效。
  • layoutSubviews:对subviews进行布局,不能主动调用,需要的时候在子类重写,系统会在合适的时候自动调用。
  • 注意 : 如果要立即刷新frame,要先调用setNeedsLayout(),把标记设为需要布局,然后马上调用layoutIfNeeded(),实现布局。
  • setNeedsUpdateConstraints:告知需要更新约束,但是不会立刻开始
  • updateConstraintsIfNeeded:告知立刻更新约束
  • updateConstraints:系统更新约束

(2)系统调用layoutSubviews的时机

  • init初始化不会触发layoutSubviews,但是使用initWithFrame进行初始化且rect不为zero时,会调用layoutSubviews。
  • addSubview的时候会触发系统调用layoutSubviews。
  • 当view的frame发生改变的时候触发layoutSubviews。
  • 滚动一个UIScrollView会触发layoutSubviews。
  • 旋转Screen会触发父UIView上的layoutSubviews事件。
  • 改变一个UIView大小的时候也会调用父UIView上的layoutSubviews事件。

具体细节可以参考:http://www.code4app.com/blog-822415-3151.html

(3)什么时候使用frame布局,什么时候选用Auto Layout布局

简单的 UI 使用 Auto Layout ,复杂的 UI 使用 frame。原因如下:

  • 从代码量上来看,两种布局方式相差不大。有时候发现复杂的 UI 使用 Auto Layout 的话,代码量反而会变多,因为复杂的 UI 往往会有复杂的逻辑,比如根据数据的不同,部分 UI 的显示会有变动(比如某个子视图隐藏与显示, 会影响到其它视图的布局)。
  • 固定的UI简单的布局,这种情况下使用 Auto Layout 还是挺方便的,具有快速、方便、简洁的布局效果。
  • 动态复杂的 UI 布局,这种情况下使用 Auto Layout 来布局,感觉就不合适。因为不管是 frame 还是 Auto Layout,都需要去计算高度,Auto Layout通过 Cassowary 算法计算各个子视图的位置,算出来后将子视图的 frame 从 Layout Engine 里拷贝出来;而frame布局,则可以快速的通过事先约定的布局计算出相应的frame,再进行相应的绘制、渲染。这种情况下,直接使用 frame 会比较精简。

Auto Layout详解相关推荐

  1. hibernate.hbm2ddl.auto配置详解

    hibernate.hbm2ddl.auto配置详解 http://www.cnblogs.com/feilong3540717/archive/2011/12/19/2293038.html hib ...

  2. auto关键字详解 C++

    C++98 auto 早在C++98标准中就存在了auto关键字,那时的auto用于声明变量为自动变量,自动变量意为拥有自动的生命期,这是多余的,因为就算不使用auto声明,变量依旧拥有自动的生命期: ...

  3. RecycleView Layout 详解

    前提 我们以RecycleView 的宽高都是Match_Parent作为前提去分析,这样onMeasure方法就不会调用dispatchStep1.dispatchStep2.我们只看onLayou ...

  4. C++中的 auto类型详解

    auto是c++程序设计语言的关键字.用于两种情况 (1)声明变量时根据初始化表达式自动推断该变量的类型 (2)声明函数时函数返回值的占位符 参考文章:c++ auto类型用法总结

  5. hibenate.hbm2ddl.auto属性详解

    hibernate配置属性中,hibernate.hbm2ddl.auto可以帮助你实现正向工程,即由java代码生成数据库脚本,进而生成具体的表结构.      在hibernate.cfg.xml ...

  6. Nhibernate.hbm2ddl.auto配置详解

    hibernate.cfg.xml 中hibernate.hbm2ddl.auto配置节点如下: <properties> <property name="hibernat ...

  7. View 绘制体系知识梳理(4) 绘制过程之 Layout 详解

    一.布局的起点 - performTraversals 和前面分析测量过程类似,整个布局的起点也是在ViewRootImpl的performTraversals当中: private void per ...

  8. [zz] Android五大布局Layout详解

    ref: http://blog.csdn.net/llping2011/article/details/9992941?utm_source=tuicool Remark  最常用的:LinearL ...

  9. width和height的默认值auto与%详解(附案例)。

    结论 点击这里有一篇关于width与height文章 width的%:定义基于包含块(父元素)宽度的百分比宽度,会突破父级的限制 width的auto:尽量被父级包裹 height的%:基于包含它的块 ...

  10. Android系统布局——android.R.layout详解

    布局文件,作为android中必不可少的一部分,android系统为了方便开发人员,在系统中定义了很多的布局文件. 系统布局文件和我们自定义的布局在写法用前缀android以示区别: 系统布局文件:a ...

最新文章

  1. 斯坦福CS329S:机器学习系统设计,课程、笔记上线了!
  2. Android UI滑动加载源码
  3. 2022 开工大吉 新的一年新的目标
  4. nginx php动态编译加载模块.
  5. SAP关于销售来自可选工厂的解决方案
  6. 一句话讲清楚IOC容器以及什么时候使用@Autowired
  7. 查看 Linux 系统版本(发行版本)信息的相关命令语句
  8. Mint-ui中loadmore(上拉加载下拉刷新)组件在ios中滑动会触发点击事件的解决方法...
  9. CSS 选择器优先级
  10. IFIX 需要权限打开某个画面
  11. php和python-Python与PHP:有什么区别?
  12. 初、中、高级Java工程师有哪些区别?
  13. matlab晶闸管不能连接,基于MATLAB的晶闸管触发电路.doc
  14. 学生报告-大学生活经验
  15. OriginPro中三维图片旋转
  16. 解决问题:failed to lazily initialize a collection of role异常解决
  17. Java poi ppt图片置于底层_POI之PPT图片插入简单实例
  18. php pecl_http,安装 PHP 的 PECL HTTP 扩展
  19. ZYT and LBC
  20. Vue组件之间的通信-父传子-子传父

热门文章

  1. 北斗/GPS模块输出的NMEA 0183语句详解
  2. Charles工具基本使用详解
  3. DAC、ADC、FFT使用总结
  4. 华为服务器重装操作系统,华为服务器安装操作系统
  5. pdg转换为pdf的方法
  6. 西数linux驱动程序,下载:西数移动硬盘WD SES Driver驱动更新
  7. 《史蒂夫·乔布斯传》(Steve Jobs)官方正式中文版高清PDF
  8. Unity代码分享——一个快速显示所有Sprite为Image_icon的帮助类
  9. java 模拟ping_模拟Ping操作的一个Java类
  10. stm32烧写序列号