YongSir

专业程序员伪装者

AutoLayout的一些经验

AutoLayout by YongSir🇨🇳🇨🇳

-----玩儿AutoLayout所得-----

  • 遇到很难布局的情况,不要忘了使用辅助视图,特别是对某些系统提供紧密的UI的时候

如想为UINavigationBar添加一个代头像和title的titleView时,因为titleView本身只有width可设置,那么如何保证正好内容剧中呢?当然给你的内容得到父视图的宽度,首先是想到设置futherVIew的Huging/Compression - Priority,但是无论如何都是不行的,原因即在于系统默认提供的navigationItem.titleView是设置Autosizingmask的,所以这时就要借助一个辅助性的containerView了,image和titleLb都加到containerView上,在设置containerView的center等于titleViewcenter,就不用去管如何自适应width的为题了,总之: 在怎么设置都不行的情况下,记的考虑添加只约束centerX 和 centerY 的辅助试图, like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

private let titleView: UIView = {
let view = UIView(frame: CGRectMake(0, 0, 100, 40))
return view
}()
private let titleLb: UILabel = {
let view = UILabel()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private let userImageView: UIImageView = {
let view = UIImageView()
view.layer.cornerRadius = 20.0
view.layer.masksToBounds = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()

override func viewDidLoad() {
super.viewDidLoad()
notificationsKeyboard()

setUpNavBar()
setUpView()
}

private func setUpNavBar() {

let continarView = UIView()
continarView.translatesAutoresizingMaskIntoConstraints = false
continarView.addSubview(userImageView)
continarView.addSubview(titleLb)
titleView.addSubview(continarView)

// debuge
titleLb.text = "JASdfasfasdON"
userImageView.image = UIImage(named: "demoAlbum")?.resizeWithWidth(40.0)

let viewsDict = ["userImageView" : userImageView,
"titleLb" : titleLb,
"continarView" : continarView]
let vflDict = ["H:|[userImageView(40)]-5-[titleLb]|",
"V:|[userImageView(40)]|"]
continarView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(vflDict[0] as String, options: .AlignAllCenterY, metrics: nil, views: viewsDict))
continarView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(vflDict[1] as String, options: [], metrics: nil, views: viewsDict))
titleView.addConstraint(NSLayoutConstraint(item: continarView, attribute: .CenterX, relatedBy: .Equal, toItem: titleView, attribute: .CenterX, multiplier: 1.0, constant: 0))
titleView.addConstraint(NSLayoutConstraint(item: continarView, attribute: .CenterY, relatedBy: .Equal, toItem: titleView, attribute: .CenterY, multiplier: 1.0, constant: 0))

navigationItem.titleView = titleView

let item: UIBarButtonItem = UIBarButtonItem(title: "...", style: .Plain, target: self, action: #selector(settingBtnClicked))
navigationItem.rightBarButtonItem = item
}
  • 发现在设置跟父空间关系时,如果想用centterX/Y来约束,还是用系统那个繁琐的方法比较便利
    所以即便是拥有VFL,也不能忘了恶心的原装方法,比较合理的是这俩结合着用
    单单是设计高度和宽度时,选用恶心方法

  • 要注意通过VFL添加的约束本身就是NSArray,这和原装的返回NSLayoutContaint不同
    在addContaint/s 时要注意,如果对应不正确,就会有这样的错误:

    Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Invalid parameter not satisfying: [constraint isKindOfClass:[NSLayoutConstraint class]]’

  • 注意约束的添加,绝大多数都是添加到当前的super,两个View之间有但很少,如果添加错误就可能会报
    这样一 坨错误:

    The view hierarchy is not prepared for the constraint:
    When added to a view, the constraint’s items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.

    以及

    1
    2
    3
    4
    5
    6
    View hierarchy unprepared for constraint.
    Constraint: <NSLayoutConstraint:0x7fb853f23910 YRViewOfUnlock:0x7fb853f218b0.leading == UIView:0x7fb853f12a70.leadingMargin>
    Container hierarchy:
    <YRViewOfUnlock: 0x7fb853f218b0; frame = (0 0; 0 0); layer = <CALayer: 0x7fb853f21bd0>>
    View not found in container hierarchy: <UIView: 0x7fb853f12a70; frame = (0 0; 375 667); autoresize = RM+BM; layer = <CALayer: 0x7fb853f11d70>>
    That view's superview: NO SUPERVIEW
  • 如果约束都添加了而没有任何效果,要注意检查autoSize( translatesAutoresizingMaskIntoConstraints)是否关闭了
    为了避免这样的错误,将AutoLayout的使用流程化:

    1. 创建元素,关闭 translatesAutoresizingMaskIntoConstraints
    2. 添加到父空间
    3. 设置约束
      否则就是这样的错误:
    1
    2
    3
    Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse constraint format:
    Unable to interpret '|' character, because the related view doesn't have a superviewV:|-top-[btn(80)]
    ^'