SnapKit:如何以编程方式为 TableView Cell 中的项目设置布局约束

SnapKit: How to set layout constraints for items in a TableViewCell programatically

我是 swift/iOS 开发的初学者。来自网络开发人员,与 DOM/Box 模型相比,布局模型完全让我感到困惑。我知道这意味着全神贯注,但就我的生活而言,我似乎无法弄明白,我希望像这样的基本示例可能有助于说明一些事情,即使我正在使用 DSL像 snapkit:http://snapkit.io/

我怎样才能为如下布局构建约束:

到目前为止,我所知道的显然是错误的如下:

label1.snp.makeConstraints { (make) -> Void in
  make.leading.equalTo(Style.MARGIN)
  make.trailing.equalTo(-Style.MARGIN)
  make.centerX.equalTo(self)
  make.top.equalTo(Style.MARGIN)
}

label2.snp.makeConstraints { (make) -> Void in
  make.leading.equalTo(Style.MARGIN)
  make.trailing.equalTo(-Style.MARGIN)
  make.centerX.equalTo(self)
  make.top.equalTo(label1.snp.bottom)
}

exampleImage.snp.makeConstraints { (make) -> Void in
  make.leading.equalTo(0)
  make.trailing.equalTo(0)
  make.top.equalTo(label2.snp.bottom).offset(Style.MARGIN)
  make.bottom.equalTo(0)
}

其中 Style.MARGIN 只是一个常量设置为 20

我觉得我只需要看一个这样的例子就可以了解布局的流程和构建方式,也许可以像网站一样构建它。 我认为在最基本的层面上,对我来说最令人困惑的事情是理解如何将不同动态高度的对象放在前一个对象的下方,并让 tableViewCell 也相应地调整大小。

这是您在添加约束时必须直接或间接指定的事项列表:

  • X位置
  • Y位置
  • 宽度
  • 身高

在做约束时考虑这些事情中的每一件事可以使这变得非常简单。

第一,label1.

  1. X位置:我们希望它水平居中
  2. Y 位置:距离其超级视图顶部 20
  3. Width: 一些数字,使得它的左边距离父视图的左边20,右边距离父视图的右边20,这也意味着X位置
  4. 身高:您没有在屏幕截图中指定。我假设你希望它的高度是超级视图的 1/3

这转化为以下约束:

make.topMargin.equalTo(20)
make.leftMargin.equalTo(20)
make.rightMargin.equalTo(-20)
make.height.equalToSuperview().dividedBy(3)

现在 label2:

  1. X位置:我们希望它水平居中
  2. Y 位置:从 label1
  3. 底部算起 10
  4. 宽度:一些数字,使得它的左边距离父视图的左边20,右边距离父视图的右边20,这也意味着它的X位置
  5. 高度:距离超级视图底部 20 的一些数字

这转化为:

make.top.equalTo(label1.snp.bottom).offset(10)
make.leftMargin.equalTo(20)
make.rightMargin.equalTo(-20)
make.bottomMargin.equalTo(-20)

您也可以使用 UIStackView 来实现这一点。

有关如何使 table 视图根据内容调整其单元格高度的大小,请参阅 this

自 iOS9 以来,许多像这样的简单布局都可以使用 UIStackViews 构建,UIStackViews 是管理子视图及其布局约束的容器视图,因此您不必(像怀旧评论家那样) .

除了概念简单之外,UIStackViews 对他们有很多好处。它们性能良好,易于使用,并且无需手动操作和更新大量约束即可轻松隐藏/显示视图。

在这种情况下,您有两个 UILabel 和一个 UIImageView 以一定间距堆叠在一起。如果我要实现这个布局,我会将两个标签组合在一个 UIStackView 中,将它添加到一个带有一些插图的 UIView,然后将该视图与 UIImageView 一起添加到另一个 UIStackView,如下所示:

UIStackView (1)

UIView (2)

UIStackView (3)

UILabel (4)

UILabel (5)

UIImageView (6)

在代码中:

let containerStackView = UIStackView() // (1)
containerStackView.axis = .vertical

let greenLabel = UILabel() // (4)
greenLabel.text = "Hello,"

let blueLabel = UILabel() // (5)
blueLabel.text = "World!"

let textStackView = UIStackView() // (3)
textStackView.axis = .vertical
textStackView.spacing = 10
textStackView.addArrangedSubview(greenLabel)
textStackView.addArrangedSubview(blueLabel)

let textContainerView = UIView() // (2)
textContainerView.addSubview(textStackView)
textStackView.snp.makeConstraints { make in
    make.edges.equalToSuperview().inset(20)
}

let imageView = UIImageView(image: UIImage(named: "my-image") // (6)
containerStackView.addArrangedSubview(textContainerView)
containerStackView.addArrangedSubview(imageView)

然后您需要将容器堆栈视图限制为您的 UITableViewCell 的内容视图:

contentView.addSubview(containerStackView)
containerStackView.snp.makeConstraints { make in
    make.edges.equalToSuperview()
}

这就是我要做的。当然,您自己管理约束的方法同样有效,可以按如下方式完成:

contentView.addSubview(label1)
label1.snp.makeConstraints { make in
    make.leading.equalToSuperview().offset(20)
    make.trailing.equalToSuperview().offset(-20)
    make.top.equalToSuperview().offset(20)
}

contentView.addSubview(label2)
label2.snp.makeConstraints { make in
    make.leading.equalToSuperview().offset(20)
    make.trailing.equalToSuperview().offset(-20)
    make.top.equalTo(label1.snp.bottom).offset(10)
}

contentView.addSubview(exampleImage)
exampleImage.snp.makeConstraints { make in
    make.leading.trailing.bottom.equalToSuperview()
    make.top.equalTo(label2.snp.bottom).offset(20)
}

请注意,我是用文本编辑器写的,所以可能会有一些拼写错误,但大意应该是成立的。