0

I have implemented expand/ collapse animation, for a UICollectionView with dynamic cell height (Because different cell has different content).

This is the summary of my implementation

  1. I am using UICollectionViewCompositionalLayout, because I want the cell able to adjust its own height to accommodate its content. (https://stackoverflow.com/a/51231881/72437)
  2. I am using UIStackView in the cell. Reason is that, once I hide one of the UITextViews in the cell, I do not want the hidden UITextView to still occupy the space. Using UIStackView can avoid me from dealing with zero height constraint.
  3. I am using performBatchUpdates and layoutIfNeeded to achieve the animation, based on https://stackoverflow.com/a/69043389/72437

Here's the final outcome - https://www.youtube.com/watch?v=2uggmpk0tJc

As you can see, the overall effect isn't really smooth, espcially when I toggle in between "Color" and "Print PDF", which are having larger content height.

This is what happen when I tap on the cell

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    var indexPaths = [IndexPath]()
    
    for i in (0..<isExpanded.count) {
        if isExpanded[i] != false {
            isExpanded[i] = false
            
            indexPaths.append(IndexPath(item: i, section: 0))
        }
    }
    
    if isExpanded[indexPath.item] != true {
        isExpanded[indexPath.item] = true
        
        indexPaths.append(IndexPath(item: indexPath.item, section: 0))
    }
    
    collectionView.performBatchUpdates({}) { _ in
        collectionView.reloadItems(at: indexPaths)
        collectionView.layoutIfNeeded()
    }
}

Do you have any idea, what else thing I can try out, so that the animation will look smoother? This is the complete code example for demonstration

https://github.com/yccheok/shop-dialog/tree/1a2c06b40327f7a4d6f744f1c3a05a38aa513556

Thank you!

Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875
  • Many, many examples of doing this with a table view... is there a specific reason you are using a collection view instead? – DonMag Apr 16 '22 at 21:11
  • There really is no such thing as a self sizing collection view cell... – matt Apr 16 '22 at 21:57
  • @DonMag We never bother to look into table view as all the problem we are looking into are solved via collection view. Hence, we do not have any experience/ knowledge in table view. – Cheok Yan Cheng Apr 17 '22 at 05:34
  • It would be best if you used the modern iOS 14 way with UICollectionView. Expending sections and cells are built into it. – Jevon718 Nov 03 '22 at 13:15

1 Answers1

2

You can get close to your goal by changing didSelectItemAt to this:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    for i in (0..<isExpanded.count) {
        if i == indexPath.item {
            // toggle selected row
            isExpanded[i].toggle()
        } else {
            // set all other rows to false
            isExpanded[i] = false
        }
        if let c = collectionView.cellForItem(at: IndexPath(item: i, section: 0)) as? CollectionViewCell {
            c._description.isHidden = !isExpanded[i]
        }
    }
    collectionView.performBatchUpdates(nil, completion: nil)
    
}

The default animation / compression of elements when showing and hiding elements in stack views is not always acceptable though. If you want to try to refine it, take a look at this discussion:

Change default StackView animation

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • Thank you for your valuable feedback. That works really well! Is this the reason why your code is working? : Performing show/ hide before performBatchUpdates, whereas my non-workable code is performing show/ hide after performBatchUpdates ? – Cheok Yan Cheng Apr 17 '22 at 07:22
  • @CheokYanCheng - the big difference is that your code was calling `.reloadItems(at: indexPaths)` which has its own animation. – DonMag Apr 17 '22 at 13:25