swift - Swift:与现代 CollectionView 中的自定义 UICollectionViewListCell 的约束冲突
问题描述
我正在使用带有 iOS14 的“现代” UICollectionView 来实现列表配置。我的实现是成功的,即单元格以动态高度大小呈现,但具有冲突的约束。
2020-12-24 19:23:50.889822+0800 circulars[18490:2636547] [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:0x60000102b250 V:|-(16)-[UIStackView:0x7f9b6ad4d120] (active, names: '|':circulars.CircularCollectionCell:0x7f9b6ad4c5f0 )>",
"<NSLayoutConstraint:0x60000102b4d0 UIStackView:0x7f9b6ad4d120.bottom == circulars.CircularCollectionCell:0x7f9b6ad4c5f0.bottom - 16 (active)>",
"<NSLayoutConstraint:0x60000102b520 'UISV-canvas-connection' UIStackView:0x7f9b6ad4d120.top == UILabel:0x7f9b6ad49320.top (active)>",
"<NSLayoutConstraint:0x60000102b570 'UISV-canvas-connection' V:[UILabel:0x7f9b6ad4ceb0]-(0)-| (active, names: '|':UIStackView:0x7f9b6ad4d120 )>",
"<NSLayoutConstraint:0x60000102b5c0 'UISV-spacing' V:[UILabel:0x7f9b6ad49320]-(8)-[UILabel:0x7f9b6ad4c930] (active)>",
"<NSLayoutConstraint:0x60000102b610 'UISV-spacing' V:[UILabel:0x7f9b6ad4c930]-(8)-[UILabel:0x7f9b6ad4ceb0] (active)>",
"<NSLayoutConstraint:0x60000101dd60 'UIView-Encapsulated-Layout-Height' circulars.CircularCollectionCell:0x7f9b6ad4c5f0.height == 44 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000102b610 'UISV-spacing' V:[UILabel:0x7f9b6ad4c930]-(8)-[UILabel:0x7f9b6ad4ceb0] (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
代码:
class TestController: UIViewController {
lazy var collectionView: UICollectionView = {
let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
let layout = UICollectionViewCompositionalLayout.list(using: config)
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.backgroundColor = .systemBackground
cv.delegate = self
return cv
}()
var dataSource: UICollectionViewDiffableDataSource<Section, Circular>?
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
setupData()
}
func setupViews() {
view.backgroundColor = .systemBackground
navigationItem.title = "CV"
view.addSubview(collectionView)
collectionView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
setupCell()
}
func setupCell() {
//No constraint conflict for this cell section
let registration = UICollectionView.CellRegistration<UICollectionViewListCell, Circular> { (cell, indexPath, circular) in
var content = cell.defaultContentConfiguration()
content.text = circular.title
cell.contentConfiguration = content
}
//Constraint conflict for this cell/section.
let cirRegistration = UICollectionView.CellRegistration<CircularCollectionCell, Circular> { (cell, indexPath, circular) in
cell.circular = circular
}
dataSource = UICollectionViewDiffableDataSource<Section, Circular>(collectionView: collectionView) { (collectionView, indexPath, circular) -> UICollectionViewCell? in
if indexPath.section == 0 {
return collectionView.dequeueConfiguredReusableCell(using: registration, for: indexPath, item: circular)
} else {
return collectionView.dequeueConfiguredReusableCell(using: cirRegistration, for: indexPath, item: circular)
}
}
}
func setupData() {
let circulars = [
//Setup circulars
]
populate(circulars: circulars)
}
func populate(circulars: [Circular]) {
var snapshot = NSDiffableDataSourceSnapshot<Section, Circular>()
snapshot.appendSections([.main, .second])
snapshot.appendItems(circulars, toSection: .main)
snapshot.appendItems(Array(circulars.prefix(2)), toSection: .second)
dataSource?.apply(snapshot)
}
}
extension TestController {
enum Section {
case main, second
}
}
//At custom CircularCollectionCell
class CircularCollectionCell: UICollectionViewListCell {
var companyLabel: UILabel = {
let l = UILabel()
l.translatesAutoresizingMaskIntoConstraints = false
l.numberOfLines = 0
l.font = UIFont.systemFont(ofSize: 15, weight: .heavy)
return l
}()
var titleLabel: UILabel = {
let l = UILabel()
l.translatesAutoresizingMaskIntoConstraints = false
l.numberOfLines = 0
l.font = UIFont.systemFont(ofSize: 17, weight: .medium)
return l
}()
var dateLabel: UILabel = {
let l = UILabel()
l.translatesAutoresizingMaskIntoConstraints = false
l.numberOfLines = 0
l.font = UIFont.systemFont(ofSize: 14, weight: .light)
l.textColor = .systemGray
return l
}()
var circular: Circular? {
didSet {
if let circular = circular {
//Setup UI
dateLabel.text = circular.date
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
let stackView = UIStackView(arrangedSubviews: [
companyLabel,
titleLabel,
dateLabel
])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.spacing = 8
addSubview(stackView)
stackView.topAnchor.constraint(equalTo: topAnchor, constant: 16).isActive = true
stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16).isActive = true
stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16).isActive = true
stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16).isActive = true
}
}
解决方案
避免冲突约束问题的一种方法是给出一个约束,它负责高度,即topAnchor
更高的优先级:
let topAnchorConstraint = stackView.topAnchor.constraint(equalTo: topAnchor, constant: 16)
topAnchorConstraint.priority = .defaultHigh // Also used sometimes: UILayoutPriority(999)
topAnchorConstraint.isActive = true
因为这个约束现在具有更高的优先级,UIView-Encapsulated-Layout-Height
被否决并且冲突是可以解决的。
推荐阅读
- machine-learning - 使用 Pytorch 预测舞蹈帧
- r - 如何使用 R 中的文本函数将方程添加到我的绘图中?
- json - 如何以模块化形式在 Terraform 中使用 s3 生命周期规则,即在单独的 JSON 中引用?
- android - 如何从 kotlin 中的 volley response liatner 在 recyclerview 中设置数据?
- django - 如何从 django 中的多个表中获取数据
- rust - Actix TCP 客户端实现的编译问题
- sql - 进行 1 对 1 多字段 SQL 联接,其中只有一些值匹配
- c# - ASP.NET,Entity Framework Code First 多对多自引用列表
- python - 如何使用 Python 从统计跟踪网站 (cod.tracker.gg) 抓取正确的元素
- java - android.widget.ProgressBar 不能转换为 android.widget.RelativeLayout