[Android开发学iOS系列] Auto Layout

[Android开发学iOS系列] Auto Layout内容:

  • 介绍什么是Auto Layout.
  • 基本使用方法
    • 在代码中写约束的方法
  • Auto Layout的原理
  • 尺寸和优先级
  • Auto Layout的使用细则
    • 重要的属性
    • StackView
    • Layout Guide
  • Performance
  • Debugging
What is Auto LayoutAuto Layout会根据constraints(约束)动态计算出view hierarchy中所有View的位置和大小.
对于Android开发者来说, Auto Layout很容易上手, 它非常像ConstraintLayoutRelativeLayout: 给View规定它上下左右和谁对齐, 决定UI的位置和大小.
Auto Layout的约束更宽泛一些, 不仅仅是两个View之间的关系, 还有宽高, 比率等设置, 并且可以有一些大于小于等的范围设置.
Auto Layout不是一个View开始学Auto Layout我还以为它是一个叫AutoLayout的View, 把其他子View包进去然后设置一些放置规则, 就类似于Android的ConstraintLayout或者RelativeLayout.
但是其实不是, AutoLayout不是一个具体的View, 它代表的是一种计算引擎. 因为在代码里你从来不需要写AutoLayout这个关键字, 写的从来都是Constraints.
开发者为View设置足够多的约束, 规定和这个View位置和大小相关的因素, 这个引擎就可以为我们计算出View的位置和大小.
AutoLayout为了解决什么问题不同屏幕适配; 可以合理应对变化的responsive UI.
改变布局有内外两种因素, 除了屏幕尺寸, 屏幕旋转, 窗口大小改变等外部因素.
内部因素还包含了内容的动态变化, 国际化的支持, 字体的调整等.
和Auto Layout平行的解决方案是什么摆放UI有三种主要的方法:
  • 在程序里给每个View设置frame.
  • 设置frame, 结合使用autoresizing masks来应对外部变化. (autoresizing mask定义了一个view的frame在它的superview frame变化时应该如何变化.)
  • 使用Auto Layout.
可以看出第二种只是在基于frame的方式上做出了一点改进, 所能应对的也仅仅是外部变化, 有一定的局限性. 所以可以把前两种归类为一种.
这也正是Auto Layout出现之前的解决方案, 即基于frame的布局方式.
Auto Layout的思考点不再着眼于view frame, 而是view的relationship.
如何使用Auto Layout写iOS的UI有多种方式, Auto Layout属于UIKit, 在写的时候, 可以用storyboard, 也可以直接在代码中写约束.
在storyboard里面有一些好处, 比如所见即所得, 而且ide会给出一些warnings, 比如控件在storyboard上的位置与约束不一致, 会提示, 并且可以选择方式修复.在storyboard里面写约束确实是不容易出错的一种方式, xcode的操作也很直观, 这里不做演示了.
之前我们也讨论过, 用storyboard写UI存在阅读性差, 代码版本管理和团队合作都有问题等.所以具体使用需要看实际情况.
关于约束, location和size的约束不能混着用, 这个也是从逻辑上就可以理解的.比如让某个view的top和parent的top对齐(或者再offset个常量)是可以的, 但是让top等于某个size就不能理解了.
在代码中创建约束如果不用Interface Builder, 而是选择在代码中创建约束, 那么仍然有多种选择:
  • 使用layout anchor.
  • 使用NSLayoutConstraint类.
  • 使用Visual Format Language.
我们在改变约束的时候通常不会add/remove constraints, 而是active/deactivate.
使用Layout anchor这个方法可能是最直观的一种方法.
// Get the superview's layoutlet margins = view.layoutMarginsGuide// Pin the leading edge of myView to the margin's leading edgemyView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true// Pin the trailing edge of myView to the margin's trailing edgemyView.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true// Give myView a 1:2 aspect ratiomyView.heightAnchor.constraint(equalTo: myView.widthAnchor, multiplier: 2.0).isActive = true这里我们把每一条约束设置了isActive = true.
也可以直接放在一个数组里一起activate, 会有性能优势:
NSLayoutConstraint.activate([myView.leadingAnchor.constraint(equalTo: margins.leadingAnchor),myView.trailingAnchor.constraint(equalTo: margins.trailingAnchor),myView.heightAnchor.constraint(equalTo: myView.widthAnchor, multiplier: 2.0)])使用NSLayoutConstraint使用NSLayoutConstraint写起来比较啰嗦, 必须给每个参数都指定值:
NSLayoutConstraint(item: myView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = trueNSLayoutConstraint(item: myView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = trueNSLayoutConstraint(item: myView, attribute: .height, relatedBy: .equal, toItem: myView, attribute:.width, multiplier: 2.0, constant:0.0).isActive = true

推荐阅读