繁体   English   中英

UICollectionView 高度在第一次加载时调整大小

[英]UICollectionView Height resizes on first load

我有一个包含堆栈视图的 UITableViewCell ( MyTableViewCell )。 stackview 中的第一项是一个子视图( MyHeaderView ),其中包含一些标签和一个UICollectionView 当 tableview 最初加载UICollectionView的高度大于内容时,我遇到了一个问题,然后它会缩回/跳转到正确的大小(初始高度大约是内容的两倍)。 只有当UICollectionView中的项目超过 1 行时才会发生这种情况。

class MyHeaderView: UIView {

    private var identifierLabel = UILabel()
    private var statementLabel = UILabel()
    private var referenceIdLabel = UILabel()

    private var tagsCollectionView: DynamicHeightCollectionView!

    private var tagsArray = [String]()
    private var tags = [String]()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    func commonInit() {
        initTagsCollectionViewLayout()

        backgroundColor = .red
        self.addSubview(contentView)
        contentView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }

        contentView.addSubview(identifierLabel)
        contentView.addSubview(tagsCollectionView)
        contentView.addSubview(statementLabel)
        contentView.addSubview(referenceIdLabel)

        identifierLabel.layer.borderWidth = 4
        identifierLabel.layer.borderColor = UIColor.white.cgColor
        identifierLabel.snp.makeConstraints { make in
            make.top.equalToSuperview()
            make.leading.equalToSuperview()
            make.width.lessThanOrEqualTo(30)
            make.height.equalTo(30)
        }

        tagsCollectionView.snp.makeConstraints { make in
            make.top.equalTo(identifierLabel.snp.bottom)
            make.leading.equalToSuperview()
            make.trailing.equalToSuperview()
        }

        referenceIdLabel.numberOfLines = 0
        referenceIdLabel.snp.makeConstraints { make in
            make.top.equalTo(tagsCollectionView.snp.bottom)
            make.leading.equalToSuperview()
            make.trailing.equalToSuperview()
        }

        statementLabel.numberOfLines = 0
        statementLabel.snp.makeConstraints { make in
            make.top.equalTo(referenceIdLabel.snp.bottom)
            make.leading.equalToSuperview()
            make.trailing.equalToSuperview()
            make.bottom.equalToSuperview()
        }
    }

    lazy var contentView: UIView = {
        let view = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 400))
        view.layer.borderWidth = 4
        view.layer.borderColor = UIColor.white.cgColor

        view.backgroundColor = UIColor.red
        return view
    }()

    func initTagsCollectionViewLayout() {
        let flowLayout = LeftAlignedCollectionViewFlowLayout()

        tagsCollectionView = DynamicHeightCollectionView(frame: .zero, collectionViewLayout: flowLayout)

        tagsCollectionView.delegate = self
        tagsCollectionView.dataSource = self
        tagsCollectionView.isScrollEnabled = false
        tagsCollectionView.backgroundColor = .white

        flowLayout.estimatedItemSize = CGSize(width: 50, height: 20)
        flowLayout.minimumInteritemSpacing = 4
        flowLayout.minimumLineSpacing = 8
        flowLayout.scrollDirection = .vertical

        self.tagsCollectionView.collectionViewLayout = flowLayout
        self.tagsCollectionView.layoutIfNeeded()
        self.tagsCollectionView.register(UINib.init(nibName: Constants.tagsCollectionCellNibName, bundle: nil), forCellWithReuseIdentifier: Constants.tagsCollectionCellReuseID)
    }

    // MARK: Set up view
    func setUpView(observation: Observation) {
        identifierLabel.text = observation.identifier
        statementLabel.text = observation.statement
        referenceIdLabel.text = observation.referenceID

        tagsArray = [String]()

        if let tags = observation.tags, tags.count > 0 {
            for tag in tags {
                tagsArray.append(tag)
            }
        }

        if tagsArray.count > 0 {
            tagsCollectionView.reloadData()
            //tagsCollectionView.setNeedsLayout()
            tagsCollectionView.layoutIfNeeded()
        }
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        if (self.superview != nil) {
            self.superview?.layoutIfNeeded()
        }

        return tagsCollectionView.contentSize
    }
}

extension MyHeaderView: UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return tagsArray.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        var cell = UICollectionViewCell()

        switch collectionView {
        case tagsCollectionView:
            let tagsCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: Constants.tagsCollectionCellReuseID, for: indexPath) as! TagsCollectionViewCell

            tagsCollectionViewCell.initRequirementTag(tagText: self.tagsArray[indexPath.item])

            cell = tagsCollectionViewCell

        default:
            break
        }

        return cell
    }
}

// MARK: - Constants
private enum Constants {
    static let tagsCollectionCellReuseID = "TagsCollectionViewCell"
    static let tagsCollectionCellNibName = "TagsCollectionViewCell"
}








class MyTableViewCell: UITableViewCell {

    private var stackView = UIStackView()
    private var myHeaderView = MyHeaderView()
    private var observation: Observation?


    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    func commonInit() {
        self.addSubview(stackView)

        stackView.axis = .vertical
        stackView.spacing = 4
        stackView.distribution = .fillProportionally
        stackView.alignment = .fill
        stackView.arrangedSubviews.forEach({ $0.removeFromSuperview() }) // clear stack view on each load

        stackView.addArrangedSubview(myHeaderView)

        stackView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            //make.width.equalToSuperview()
        }

        myHeaderView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }

    }

    func setupView(observation: Observation) {
        self.observation = observation

        myHeaderView.setUpView(observation: observation)
    }

}





class DynamicHeightCollectionView: UICollectionView {

    override func layoutSubviews() {
        super.layoutSubviews()
        if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
            self.invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }
}

class LeftAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributes = super.layoutAttributesForElements(in: rect)

        var leftMargin = sectionInset.left
        var maxY: CGFloat = -1.0
        attributes?.forEach { layoutAttribute in
            if layoutAttribute.frame.origin.y >= maxY {
                leftMargin = sectionInset.left
            }

            layoutAttribute.frame.origin.x = leftMargin

            leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
            maxY = max(layoutAttribute.frame.maxY , maxY)
        }

        return attributes
    }
}




// in tableview controller
var obs1 = Observation(identifier: "1.1", statement: "custom statement test", referenceID: "reference id test", tags: ["tag 1", "tag 2", "tag 3", "tag 4", "tag 5", "tag 6", "tag 7", "tag 8", "tag 9", "tag 10", "tag 11", "tag 12", "tag 13", "tag 14", "tag 15", "tag 16", "tag 17", "tag 18", "tag 19", "tag 20"])

    var obs2 = Observation(identifier: "1.2", statement: "custom statement test thats runs onto multiple lines, custom statement test thats runs onto multiple lines, custom statement test thats runs onto multiple lines, custom statement test thats runs onto multiple lines", referenceID: "reference id test that runs onto multiple lines, reference id test that runs onto multiple lines reference id test that runs onto multiple lines reference id test that runs onto multiple lines reference id test that runs onto multiple lines", tags: ["tag 1", "tag 2", "tag 3", "tag 4", "tag 5", "tag 6", "tag 7", "tag 8"])

    var obs3 = Observation(identifier: "1.3", statement: "custom statement test", referenceID: "reference id test", tags: [])

    var obs4 = Observation(identifier: "1.4", statement: "custom statement test", referenceID: "reference id test", tags: [])

var obs: [Observation]
obs.append(obs1)
obs.append(obs2)
obs.append(obs3)
obs.append(obs4)

struct Observation {
    var identifier: String
    var statement: String
    var referenceID: String
    var tags: [String]
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ObservationTableViewCellV2") as! ObservationTableViewCellV2

        let observation = obs[indexPath.row] as! Observation
        cell.setupView(observation: observation)

        return cell
    }

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return obs.count
    }

我已经尝试更改估计的项目大小和UICollectionViewDelegateFlowLayout sizeForItemAt但它没有区别。

UICollectionView以蓝色突出显示。 在第一次加载时,它显示为: 在此处输入图像描述

然后一瞬间它调整到正确的大小: 在此处输入图像描述

在 storyboard 内部 Size Inspector 部分中,将 Collection View 上的Estimate SizeAutomatic设置为None

当您将包含集合视图的单元格出列时,请检查其宽度。 它可能小于 tableview 的宽度(可能是 320?)。 将其设置为更大的值,例如 tableView 的宽度,例如在cellForRowAt indexPath:中,一旦您将其出列,则集合视图可以正确计算它的高度。 设置宽度并添加 collectionView 后,调用layoutIfNeeded()

最终,如果它正在“稍后”调整到您想要的大小,那么代码正在运行,我只能假设您需要查看代码何时运行。

我有一个类似的简单问题,我在viewDidAppear而不是viewWillAppear中放置了一些调整大小的逻辑。 做出这个简单的改变就大不相同了。

尝试在 initTagsCollectionViewLayout 内的主线程上显式运行 layoutIfNeeded。 这可能是这里的问题。

DispatchQueue.main.async {
   self.tagsCollectionView.layoutIfNeeded()
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM