How to adjust height of UICollectionView to be the height of the content size of the UICollectionView?

后端 未结 14 1005
死守一世寂寞
死守一世寂寞 2020-11-28 03:51

I would like the UICollectionView (The red one) to shrink to the height of the content size in this case UICollectionViewCells(the yellow ones) because there is a lot of emp

相关标签:
14条回答
  • 2020-11-28 04:09

    You have to set height constraint as equal to content size

    HeightConstraint.constant = collection.contentSize.height 
    
    0 讨论(0)
  • 2020-11-28 04:11
    1. Subclass UICollectionView as follows
    2. Delete height constraint if any
    3. Turn on Intrinsic Size

    -

    class ContentSizedCollectionView: UICollectionView {
        override var contentSize:CGSize {
            didSet {
                invalidateIntrinsicContentSize()
            }
        }
    
        override var intrinsicContentSize: CGSize {
            layoutIfNeeded()            
            return CGSize(width: UIView.noIntrinsicMetric, height: collectionViewLayout.collectionViewContentSize.height)
        }
    }
    
    0 讨论(0)
  • 2020-11-28 04:18

    On your UICollectionView set your constraints such as Trailing, Leading, and Bottom:

    If you look at my height constraint in more detail, as it is purely for storyboard look so I don't get errors, I have it to Remove at build time. The real height constraint is set in my code down below.

    My code for DrawerCollectionView, which is set as the collection view Custom Class:

    import UIKit
    
    class DrawerCollectionView: UICollectionView {
    
        override func didMoveToSuperview() {
            super.didMoveToSuperview()
    
            heightAnchor.constraint(equalToConstant: contentSize.height).isActive = true
        }
    }
    
    0 讨论(0)
  • 2020-11-28 04:19

    I ended up, by subclassing the UICollectionView and overriding some methods as follows.

    • Returning self.collectionViewLayout.collectionViewContentSize for intrinsicContentSize makes sure, to always have the correct size
    • Then just call it whenever it might change (like on reloadData)

    Code:

    override func reloadData() {
        super.reloadData()
        self.invalidateIntrinsicContentSize()
    }
    
    override var intrinsicContentSize: CGSize {
        return self.collectionViewLayout.collectionViewContentSize
    }
    

    But be aware, that you lose "cell re-using", if you display large sets of data, eventhough they don't fit on the screen.

    0 讨论(0)
  • 2020-11-28 04:20

    I would suggest the following:

    1. Add a height constraint to your collection view.
    2. Set its priority to 999.
    3. Set its constant to any value that makes it reasonably visible on the storyboard.
    4. Change the bottom equal constraint of the collection view to greater or equal.
    5. Connect the height constraint to an outlet.
    6. Every time you reload the data on the collection view do the following:

    You may also want to consider the Inset of the collection view by adding it to the content size.

    Code Sample:

    CGFloat height = myCollectionView.collectionViewLayout.collectionViewContentSize.height
    heightConstraint.constant = height
    self.view.setNeedsLayout() Or self.view.layoutIfNeeded()
    

    Explanation: Extra, You don't have to read if you understand it. obviously!!

    The UI will try to reflect all the constraints no matter what are their priorities. Since the height constraint has lower priority of (999), and a bottom constraint of type greater or equal. whenever, the height constraint constant is set to a value less than the parent view height the collection view will be equal to the given height, achieving both constraints.

    But, when the height constraint constant set to a value more than the parent view height both constraints can't be achieved. Therefore, only the constraint with the higher priority will be achieved which is the greater or equal bottom constraint.

    The following is just a guess from an experience. So, it achieves one constrant. But, it also tries to make the error in the resulted UI for the other un-achieved lower priority constraint as lowest as possible. Therefore, the collection view height will be equal to the parent view size.

    0 讨论(0)
  • 2020-11-28 04:22

    This seemed like the simplest solution for me.

    class SelfSizingCollectionView: UICollectionView {
        override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
            super.init(frame: frame, collectionViewLayout: layout)
            commonInit()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            commonInit()
        }
    
        private func commonInit() {
            isScrollEnabled = false
        }
    
        override var contentSize: CGSize {
            didSet {
                invalidateIntrinsicContentSize()
            }
        }
    
        override func reloadData() {
            super.reloadData()
            self.invalidateIntrinsicContentSize()
        }
    
        override var intrinsicContentSize: CGSize {
            return contentSize
        }
    }
    

    You may not need to override reloadData

    0 讨论(0)
提交回复
热议问题