【发布时间】:2018-03-14 11:59:16
【问题描述】:
我希望 UITableView 的单元格适应其内容的大小在 iOS 10 和 11 中:
tableView.estimatedRowHeight = UITableViewAutomaticDimension // default in iOS 11
tableView.rowHeight = UITableViewAutomaticDimension
没有将 tableView.rowHeight 设置为显式数值,这是 iOS 11 中的新默认值。
UIView 没有内在的内容大小,因此我为其高度锚设置了布局约束。但是,该锚在运行时会中断。
UITableViewCell 中的哪些内部约束是单元格适应其内容所必需的?
这仅适用于 iOS 11:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.estimatedRowHeight = UITableViewAutomaticDimension
tableView.rowHeight = UITableViewAutomaticDimension
tableView.delegate = self
tableView.dataSource = self
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
tableView.rightAnchor.constraint(equalTo: view.rightAnchor)
])
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cell")
let view = UIView()
view.backgroundColor = .blue
view.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(view)
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: cell.contentView.topAnchor),
view.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor),
view.leftAnchor.constraint(equalTo: cell.contentView.leftAnchor),
view.rightAnchor.constraint(equalTo: cell.contentView.rightAnchor),
view.heightAnchor.constraint(equalToConstant: 300)
])
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
}
在 iOS 10 中会引发此运行时错误,并且单元格大小不适应:
[LayoutConstraints] 无法同时满足约束。 以下列表中的至少一个约束可能是一个 你不想要。试试这个:(1)查看每个约束并尝试 找出你没想到的; (2) 找到添加的代码 不需要的约束或约束并修复它。 ( “NSLayoutConstraint:0x17009c020 V:|-(0)-[test.MyView:0x11dd1acb0](活动,名称:'|':UITableViewCellContentView:0x11dd15220)”, "NSLayoutConstraint:0x17009c160 test.MyView:0x11dd1acb0.bottom == UITableViewCellContentView:0x11dd15220.bottom (active)", "NSLayoutConstraint:0x17009c390 test.MyView:0x11dd1acb0.height == 300 (active)", "NSLayoutConstraint:0x17009be40 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x11dd15220.height == 43.6667(活动)“ )
将尝试通过打破约束来恢复 NSLayoutConstraint:0x17009c390 test.MyView:0x11dd1acb0.height == 300 (主动)
在 UIViewAlertForUnsatisfiableConstraints 创建一个符号断点 在调试器中捕获它。中的方法 UIView 上的 UIConstraintBasedLayoutDebugging 类别列于 UIKit/UIView.h 也可能有帮助。
这适用于 iOS 10 和 11,但不使用新的 iOS 11 方法,因为 tableView.estimatedRowHeight 不是 UITableViewAutomaticDimension:
class ViewController_TableView: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.estimatedRowHeight = 30
tableView.rowHeight = UITableViewAutomaticDimension
tableView.delegate = self
tableView.dataSource = self
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
tableView.rightAnchor.constraint(equalTo: view.rightAnchor)
])
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cell")
let view = MyView()
view.backgroundColor = .blue
view.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(view)
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: cell.contentView.topAnchor),
view.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor),
view.leftAnchor.constraint(equalTo: cell.contentView.leftAnchor),
view.rightAnchor.constraint(equalTo: cell.contentView.rightAnchor)
])
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
}
class MyView: UIView {
override var intrinsicContentSize: CGSize {
get {
return CGSize(width: 300, height: 300)
}
}
}
【问题讨论】:
-
这里有一些工作示例:raywenderlich.com/129059/self-sizing-table-view-cells, stackoverflow.com/questions/18746929/…;实际功能希望您设置从单元格顶部到底部的所有垂直约束,如果您错过了在 IB 中这样做。
-
@holex 我想具体了解为什么我的帖子中的简单代码示例不起作用。该代码在
rowHeight未设置为UITableViewAutomaticDimension时有效,这在 iOS 11 中不应该这样做。您的参考是 iOS 11 之前的示例。 -
在 iOS11 上,如果您将高度的约束的 priority 设置为例如
999.9,这将立即解决 break-in-runtime 问题;但这实际上并不能解释为什么首先会破坏约束... (它可能与浮点值的表示或舍入有关,但这是我的疯狂猜测) ,但是您的示例也是假设性的,因为在实践中没有人真正生成这样的 UI,所以可能没有人真正需要像以往一样面对这样的问题。 -
@holex 为什么说“没有人真正生成这样的 UI”?你能再看看我的问题吗?我觉得我最初的帖子有点混乱。
-
@holex,一位因为不了解 iOS 布局机制而逃到 IB 的开发人员遇到了完全不同的问题。比较各种开发概念的商业效率是一个有趣的话题,但我来这里是为了找到我的问题的答案。
标签: ios swift uitableview ios11 uitableviewautomaticdimension