无法同时满足约束。使用 UICollectionViewFlowLayout 自适应单元格高度

Unable to simultaneously satisfy constraints. Adaptive cell height using UICollectionViewFlowLayout

我正在尝试使用具有自适应单元格高度的 UICollectionView 制作类似应用程序的新闻提要。我找到了 并为我的代码使用了选项“2. iOS 11+ 的解决方案”,效果非常好。但是,每当我尝试向单元格添加更多子视图并根据需要对其进行布局时,我都会收到此错误:“无法同时满足约束。可能至少以下列表中的约束之一是您不想要的。”

下面是我的代码,它给我一个错误。

NewsFeedViewController:


import UIKit

class NewsFeedViewController: UIViewController {
    
    var friends: [Friend] = []
    
    var allPosts: [Post?] = []
    
    var shuffledPosts: [Post?] = []
    
    var collectionView: UICollectionView = {
        
        let layout = NewsFeedFlowLayout()
        layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize // new
        layout.scrollDirection = .vertical
        
        let collection = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collection.backgroundColor = UIColor.systemRed
        collection.isScrollEnabled = true
        collection.contentInsetAdjustmentBehavior = .always
        
        collection.translatesAutoresizingMaskIntoConstraints = false
        return collection
    }()
    
    let cellID = "NewsFeedCollectionViewCell"
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        getPosts()
        view.addSubview(collectionView)
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(NewsFeedCollectionViewCell.self, forCellWithReuseIdentifier: cellID)
        collectionView.pin(to: view)
    }
    
    func getPosts() {
        
        friends = FriendFactory().friends
        
        allPosts = friends.flatMap{[=10=].posts}
        
        var tempPosts = allPosts
        
        for _ in allPosts {
            if let index = tempPosts.indices.randomElement() {
                let post = tempPosts[index]
                shuffledPosts.append(post)
                tempPosts.remove(at: index)
            }
        }
    }
    
}


extension NewsFeedViewController: UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return shuffledPosts.count
    }
    
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as! NewsFeedCollectionViewCell
        
        let post = shuffledPosts[indexPath.row]
        let friend = friends.first(where: {[=10=].identifier == post?.authorID})
        let text = post?.postText

        cell.configurePostText(postText: text!)
        
        return cell
    }
    
}

NewsFeedCollectionViewCell:


import UIKit

class NewsFeedCollectionViewCell: UICollectionViewCell {
    
    var selectedPost = Post()

    var likeBarView: LikeBarView = {
        let view = LikeBarView()
        view.backgroundColor = .systemIndigo

        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    var postTextLabel: UILabel = {
        let label = UILabel()
        label.font = label.font.withSize(20)
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        label.backgroundColor = .systemYellow

        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        addViews()
        setupConstraints()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func addViews() {
        addSubview(likeBarView)
        addSubview(postTextLabel)
    }
    
    func configurePostText(postText: String) {
        postTextLabel.text = postText
    }
    
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    let layoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
    layoutIfNeeded()
    layoutAttributes.frame.size = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
    return layoutAttributes
}
    
    func setupConstraints() {

        NSLayoutConstraint.activate([

            likeBarView.topAnchor.constraint(equalTo: topAnchor, constant: 20),
            likeBarView.leadingAnchor.constraint(equalTo: leadingAnchor),
            likeBarView.trailingAnchor.constraint(equalTo: trailingAnchor),
            likeBarView.heightAnchor.constraint(equalToConstant: 100),

            postTextLabel.topAnchor.constraint(equalTo: likeBarView.bottomAnchor, constant: 20),
            postTextLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
            postTextLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
            postTextLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -20),
                
        ])
    }
}

NewsFeedFlowLayout:

import UIKit

final class NewsFeedFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let layoutAttributesObjects = super.layoutAttributesForElements(in: rect)?.map{ [=12=].copy() } as? [UICollectionViewLayoutAttributes]
        layoutAttributesObjects?.forEach({ layoutAttributes in
            if layoutAttributes.representedElementCategory == .cell {
                if let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame {
                    layoutAttributes.frame = newFrame
                }
            }
        })
        return layoutAttributesObjects
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        guard let collectionView = collectionView else {
            fatalError()
        }
        guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else {
            return nil
        }

        layoutAttributes.frame.origin.x = sectionInset.left
        layoutAttributes.frame.size.width = collectionView.safeAreaLayoutGuide.layoutFrame.width - sectionInset.left - sectionInset.right
        return layoutAttributes
    }

}


我附上了我得到的集合视图的截图和错误分析的截图here,这说明如果我得到,单元格的高度不是动态的没错。

我做错了什么?

将这行代码添加到 NewsFeedViewController 消除了错误:

layout.estimatedItemSize = CGSize(width: 375, height: 200)