运用 AutoLayout 的优先级例子

Dec 14, 2019 • 预计阅读时间 2 分钟

当约束条件发生冲突时,系统会使用用优先级高的约束。

还可以通过设置约束为 deactive 状态来使约束不生效。

利用好约束的优先级,可以使布局代码简洁、逻辑清晰。

系统原生的 AutoLayout 代码写起来太冗长了,使用 SnapKit 来演示如何运用约束优先级,方便理解逻辑。

场景 1 动态调整间距

当有图片的时候布局如下:

右侧有图片时

如果没有图片,文字布局如下:

没有图片时

imageView 的布局代码:

imageView.snp.makeConstraints { (make) in
    make.size.equalTo(CGSize(width: 80, height: 80))
    make.top.equalTo(100)
    make.right.equalTo(-30)
}

titleLabel 的布局代码:

var c: SnapKit.ConstraintMakerFinalizable!

titleLabel.snp.makeConstraints { (make) in
    make.top.equalTo(100)
    make.left.equalTo(30)
    c = make.right.equalTo(imageView.snp.left).offset(-10)
    make.right.equalTo(-30).priorityMedium()
}

对于 UILabel ,还需要降低其抗压缩优先级:

titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

对 titleLable 添加两条 right 约束,并降低其中一条的优先级为 medium:

make.right.equalTo(imageView.snp.left).offset(-10)
make.right.equalTo(-30).priorityMedium()

当需要显示图片时:

imageView.isHidden = false
c.constraint.activate()

没有图片时,隐藏 imageView:

imageView.isHidden = true
c.constraint.deactivate()

场景 2 动态调整宽度

布局需要满足以下需求:

  1. 手机上保持左右间距为:15
  2. 平板上使用固定宽度:320

手机上的布局效果:

手机

平板上的布局效果:

平板

可以把平板抽象为与设备无关的逻辑,目前手机上最大的尺寸是 Pro Max,它的屏幕宽度是 414。

宽度大于 414 就认为是运行于平板设备上。

布局代码如下:

var c: SnapKit.ConstraintMakerFinalizable!

containerView.snp.makeConstraints { (make) in
    make.left.equalTo(15).priorityLow()
    make.right.equalTo(-15).priorityLow()
    c = make.width.equalTo(320).priorityMedium()
    make.centerX.equalTo(view)
    make.height.equalTo(200)

    if #available(iOS 11.0, *) {
        make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-30)
    } else {
        make.bottom.equalTo(-30)
    }
}

通过约束 leftright 就能确定宽度了,再添加一条设置 width 的约束来控制最小宽度。

添加的 centerX 约束是保证 width 约束生效的时候能确定其 X 坐标位置。

不同屏幕尺寸下的显示逻辑:

if view.frame.width <= 414 {
    c.constraint.deactivate()
} else {
    c.constraint.activate()
}

场景 3 保持最小间距同时限制最大宽度

布局要求满足以下需求:

  1. 在 5s 上左右间距为 20
  2. 在 6 plus 以及更宽的屏幕上保持最大宽度为 335
  3. 水平居中显示

利用约束优先级来实现非常简单,实现代码如下:

containerView.snp.makeConstraints { (make) in
    make.left.greaterThanOrEqualTo(20).priorityHigh()
    make.right.lessThanOrEqualTo(-20).priorityHigh()
    make.width.equalTo(335).priorityMedium()
    make.centerX.equalTo(view)
}

场景 4 在 UIScrollView 里居中

布局要求满足以下需求:

  1. 上下保留最小间距 20
  2. 左右保留最小间距 20
  3. 如果空间足够则居中显示
  4. 空间不够需要能滑动查看
  5. 宽和高为 335 x 520

UIScrollView 的子控件使用自动布局时,contentSize大小由子控件的水平约束垂直约束决定。

实现代码:

containerView.snp.makeConstraints { (make) in
    // 
    make.left.greaterThanOrEqualTo(20).priorityHigh()
    make.right.lessThanOrEqualTo(-20).priorityHigh()
    make.width.equalTo(335).priorityMedium()
    make.centerX.equalTo(scrollView)
    // 
    make.top.greaterThanOrEqualTo(20).priorityHigh()
    make.bottom.lessThanOrEqualTo(-20).priorityHigh()
    make.height.equalTo(520).priorityMedium()
    make.centerY.equalTo(scrollView).priorityMedium()
}

(完)

iOS

iOS 格式化浮点数时去掉末尾的 0

导出全部 Chroma 主题 CSS 文件

comments powered by Disqus