UICollectionView Self Sizing Cells with Auto Layout

前端 未结 16 1771
野性不改
野性不改 2020-11-22 05:58

I\'m trying to get self sizing UICollectionViewCells working with Auto Layout, but I can\'t seem to get the cells to size themselves to the content. I\'m having

相关标签:
16条回答
  • 2020-11-22 06:13

    In iOS 10+ this is a very simple 2 step process.

    1. Ensure that all your cell contents are placed within a single UIView (or inside a descendant of UIView like UIStackView which simplifies autolayout a lot). Just like with dynamically resizing UITableViewCells, the whole view hierarchy needs to have constraints configured, from the outermost container to the innermost view. That includes constraints between the UICollectionViewCell and the immediate childview

    2. Instruct the flowlayout of your UICollectionView to size automatically

      yourFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
      
    0 讨论(0)
  • 2020-11-22 06:14

    In iOS10 there is new constant called UICollectionViewFlowLayout.automaticSize (formerly UICollectionViewFlowLayoutAutomaticSize), so instead:

    self.flowLayout.estimatedItemSize = CGSize(width: 100, height: 100)
    

    you can use this:

    self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    

    It has better performance especially when cells in you collection view has constant wid

    Accessing Flow Layout:

    override func viewDidLoad() {
       super.viewDidLoad()
    
       if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
          flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
       }
    }
    

    Swift 5 Updated:

    override func viewDidLoad() {
       super.viewDidLoad()
    
       if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
          flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        }
    }
    
    0 讨论(0)
  • 2020-11-22 06:20
    1. Add flowLayout on viewDidLoad()

      override func viewDidLoad() {
          super.viewDidLoad() 
          if let flowLayout = infoCollection.collectionViewLayout as? UICollectionViewFlowLayout {
              flowLayout.estimatedItemSize = CGSize(width: 1, height:1)
          }
      }
      
    2. Also, set an UIView as mainContainer for your cell and add all required views inside it.

    3. Refer to this awesome, mind-blowing tutorial for further reference: UICollectionView with autosizing cell using autolayout in iOS 9 & 10

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

    I did a dynamic cell height of collection view. Here is git hub repo.

    And, dig out why preferredLayoutAttributesFittingAttributes is called more than once. Actually, it will be called at least 3 times.

    The console log picture :

    1st preferredLayoutAttributesFittingAttributes:

    (lldb) po layoutAttributes
    <UICollectionViewLayoutAttributes: 0x7fa405c290e0> index path: (<NSIndexPath:    0xc000000000000016> 
    {length = 2, path = 0 - 0}); frame = (15 12; 384 57.5); 
    
    (lldb) po self.collectionView
    <UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 0);
    

    The layoutAttributes.frame.size.height is current status 57.5.

    2nd preferredLayoutAttributesFittingAttributes:

    (lldb) po layoutAttributes
    <UICollectionViewLayoutAttributes: 0x7fa405c16370> index path: (<NSIndexPath: 0xc000000000000016> 
    {length = 2, path = 0 - 0}); frame = (15 12; 384 534.5); 
    
    (lldb) po self.collectionView
    <UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 0);
    

    The cell frame height changed to 534.5 as our expected. But, the collection view still zero height.

    3rd preferredLayoutAttributesFittingAttributes:

    (lldb) po layoutAttributes
    <UICollectionViewLayoutAttributes: 0x7fa403d516a0> index path: (<NSIndexPath: 0xc000000000000016> 
    {length = 2, path = 0 - 0}); frame = (15 12; 384 534.5); 
    
    (lldb) po self.collectionView
    <UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 477);
    

    You can see the collection view height was changed from 0 to 477.

    The behavior is similar to handle scroll:

    1. Before self-sizing cell
    
    2. Validated self-sizing cell again after other cells recalculated.
    
    3. Did changed self-sizing cell
    

    At beginning, I thought this method only call once. So I coded as the following:

    CGRect frame = layoutAttributes.frame;
    frame.size.height = frame.size.height + self.collectionView.contentSize.height;
    UICollectionViewLayoutAttributes* newAttributes = [layoutAttributes copy];
    newAttributes.frame = frame;
    return newAttributes;
    

    This line:

    frame.size.height = frame.size.height + self.collectionView.contentSize.height;
    

    will cause system call infinite loop and App crash.

    Any size changed, it will validate all cells' preferredLayoutAttributesFittingAttributes again and again until every cells' positions (i.e frames) are no more change.

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