簡體   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