Autoresize UICollectionView height to adjust to it

2019-03-22 19:56发布

问题:

I have a UICollectionView, a button that creates a new cell in collection view. And I want UICollectionView to adjust it's size according to it's content size (when there are one or two cells then UICollectionView is short, if there are a lot of cell UICollectionView is big enough).

I know how to get content size:

collectionView.collectionViewLayout.collectionViewContentSize

But I have no idea where to use this value. I would appreciate if somebody help me to figure out how to make UICollectionView auto adjust it's height.

UPD: I published on GitHub a demo project that describes the problem: https://github.com/avokin/PostViewer

回答1:

I don't think content size is what you're after. I think you're wanting to adjust the amount of screen real estate consumed by the collection view, right? That's going to require adjustment of the frame. The content size includes the off-screen (scrolling) area as well as the on screen view.

I don't know of anything that would prevent you from just changing the frame size on the fly:

collectionView.frame = CGRectMake (x,y,w,h);
[collectionView reloadData];

If I'm understanding you correctly.



回答2:

Use a height constraint for the collection view and update its value with the content height when needed. See this answer: https://stackoverflow.com/a/20829728/3414722



回答3:

Steps to change the UICollectionView frame:

  1. Set the "translatesAutoresizingMaskIntoConstraints" property to YES for the collectioview's superview (If you are using AUTOLAYOUT)

  2. Then update the collectioview's frame as :

    collectionView.frame = CGRectMake (x,y,w,h);
    [collectionView reloadData];
    


回答4:

You need to constrain the collection view height to the height of your content:

I'm using SnapKit in the following code.

First constrain the collection view edges to its superview:

private func constrainViews() {
    collectionView?.translatesAutoresizingMaskIntoConstraints = true

    collectionView?.snp.makeConstraints { make in
        make.edges.equalToSuperview()
        heightConstraint = make.height.equalTo(0).constraint
    }
}

Next calculate the height and set the height to the height constraint offset. I'm letting the flow layout do the work, and then calculating the height based on the bottom edge of the last layout attribute:

override func viewDidLayoutSubviews() {
    guard
        let collectionView = collectionView,
        let layout = collectionViewLayout as? UICollectionViewFlowLayout
    else {
        return
    }

    let sectionInset = layout.sectionInset
    let contentInset = collectionView.contentInset

    let indexPath = IndexPath(item: tags.count, section: 0)
    guard let attr = collectionViewLayout.layoutAttributesForItem(at: indexPath) else {
        return
    }

    // Note sectionInset.top is already included in the frame's origin
    let totalHeight = attr.frame.origin.y + attr.frame.size.height
        + contentInset.top + contentInset.bottom
        + sectionInset.bottom

    heightConstraint?.update(offset: totalHeight)
}

Note that in the example, I always have one special tag not included in my items tags count, so the line:

let indexPath = IndexPath(item: tags.count, section: 0)

would need to be something like if items.count > 0 ... let indexPath = IndexPath(item: tags.count - 1, section: 0) in most other code.