Чтобы получить автоматическое измерение, работающее для UITableView.rowHeight, в моем классе UITableViewCell требуется дублирующее ограничение.
Я создаю UITableView программно (SwiftUI, без раскадровки) и имею ячейки разной высоты. Я установил для таблицы rowHeight значение UITableView.automaticDimension, но не могу найти правильную комбинацию ограничений, чтобы таблица фактически вычисляла правильную высоту для ячеек без добавления дублирующего ограничения.
Я бы хотел добавить ограничение ширины, высоты, верха и ведущего, чтобы все работало правильно. Тем не менее, таблица не будет правильно определять размер строк, если я также не добавлю нижнее ограничение. Естественно, это выдает предупреждение:
2019-10-23 18:06:53.515025-0700 Test[15858:7764405] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x600001651c20 V:|-(0)-[UIView:0x7f8fc5a08890] (active, names: '|':Aries.TestTableViewCell:0x7f8fc5a084e0'TestTableViewCell' )>",
"<NSLayoutConstraint:0x600001651e50 UIView:0x7f8fc5a08890.bottom == Aries.TestTableViewCell:0x7f8fc5a084e0'TestTableViewCell'.bottom (active)>",
"<NSLayoutConstraint:0x600001651ea0 UIView:0x7f8fc5a08890.height == 40 (active)>",
"<NSLayoutConstraint:0x600001652120 'UIView-Encapsulated-Layout-Height' Aries.TestTableViewCell:0x7f8fc5a084e0'TestTableViewCell'.height == 40.3333 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600001651ea0 UIView:0x7f8fc5a08890.height == 40 (active)>
Если я удаляю ограничение высоты или ограничение нижнего якоря, дублирующее ограничение исчезает, а предупреждение исчезает. Однако тогда таблица не будет правильно определять размер строк.
Представление:
import SwiftUI
struct TableViewTest: View {
var body: some View {
TestTableView().frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
}
}
Представление таблицы:
import SwiftUI
struct TestTableView: UIViewRepresentable {
func makeCoordinator() -> Coordinator {
Coordinator()
}
func makeUIView(context: UIViewRepresentableContext<TestTableView>) -> UITableView {
let tableView = UITableView(frame: .zero)
tableView.register(TestTableViewCell.self, forCellReuseIdentifier: "TestTableViewCell")
tableView.rowHeight = UITableView.automaticDimension
let dataSource = UITableViewDiffableDataSource<Section, TestData>(tableView: tableView) { tableView, indexPath, data in
let cell = tableView.dequeueReusableCell(withIdentifier: "TestTableViewCell", for: indexPath) as! TestTableViewCell
cell.data = data
return cell
}
populate(dataSource: dataSource)
context.coordinator.dataSource = dataSource
return tableView
}
func populate(dataSource: UITableViewDiffableDataSource<Section, TestData>) {
let items = [
TestData(color: .red, size: CGSize(width: 40, height: 20)),
TestData(color: .blue, size: CGSize(width: 40, height: 40)),
TestData(color: .green, size: CGSize(width: 40, height: 80))
]
var snapshot = NSDiffableDataSourceSnapshot<Section, TestData>()
snapshot.appendSections([.main])
snapshot.appendItems(items)
dataSource.apply(snapshot)
}
func updateUIView(_ tableView: UITableView, context: UIViewRepresentableContext<TestTableView>) {
guard let dataSource = context.coordinator.dataSource else {
return
}
populate(dataSource: dataSource)
}
class Coordinator {
var dataSource: UITableViewDiffableDataSource<Section, TestData>?
}
enum Section {
case main
}
struct TestData: Hashable {
var id = UUID()
var color: UIColor
var size: CGSize
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
}
Ячейка представления таблицы:
import UIKit
class TestTableViewCell: UITableViewCell {
var data: TestTableView.TestData? {
didSet {
if let data = data {
let view = UIView()
view.backgroundColor = data.color
addSubview(view)
// !!! SETTING THE BOTTOM ANCHOR TO NIL OR HEIGHT TO 0 PREVENTS THE TABLE FROM SIZING THE ROWS CORRECTLY
view.anchor(top: topAnchor, left: leftAnchor, bottom: bottomAnchor, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: data.size.width, height: data.size.height, enableInsets: false)
}
}
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Расширение привязки UIView:
func anchor (top: NSLayoutYAxisAnchor?, left: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, right: NSLayoutXAxisAnchor?, paddingTop: CGFloat, paddingLeft: CGFloat, paddingBottom: CGFloat, paddingRight: CGFloat, width: CGFloat, height: CGFloat, enableInsets: Bool) {
var topInset = CGFloat(0)
var bottomInset = CGFloat(0)
if #available(iOS 11, *), enableInsets {
let insets = self.safeAreaInsets
topInset = insets.top
bottomInset = insets.bottom
}
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
self.topAnchor.constraint(equalTo: top, constant: paddingTop+topInset).isActive = true
}
if let left = left {
self.leftAnchor.constraint(equalTo: left, constant: paddingLeft).isActive = true
}
if let right = right {
rightAnchor.constraint(equalTo: right, constant: -paddingRight).isActive = true
}
if let bottom = bottom {
bottomAnchor.constraint(equalTo: bottom, constant: -paddingBottom-bottomInset).isActive = true
}
if height != 0 {
heightAnchor.constraint(equalToConstant: height).isActive = true
}
if width != 0 {
widthAnchor.constraint(equalToConstant: width).isActive = true
}
}
Если я закреплю только верхний левый угол и укажу ширину и высоту в ячейке табличного представления, табличное представление не будет правильно вычислять высоту,Однако, если я также укажу высоту, строки будут иметь правильный размер, но будет сгенерировано предупреждение о двойном ограничении. Существует ли волшебная комбинация, которая позволяет правильное расположение, но не выдает предупреждение?
Плохо (но без дублирующих ограничений):
Хорошо (с дублирующими ограничениями)):