Home > Software engineering >  In UICollectionView, collapse animation is imperfect, with no height shrinking animation for the hid
In UICollectionView, collapse animation is imperfect, with no height shrinking animation for the hid

Time:04-19

Based on the problem described in

enter image description here

As you can see,

  1. The expand animation works just fine!
  2. For collapse animation, the inner UIView will disappear immediately, without any animation.

Do you have any idea, why there is no hidden animation during collapse?

Here's the code which perform collapse/ expand.

extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return shops.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let collectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? CollectionViewCell else {
            fatalError()
        }
        
        let shop = shops[indexPath.item]
        
        collectionViewCell.title.text = shop.title
        collectionViewCell._description.text = shop.description
        
        if isExpanded[indexPath.item] {
            collectionViewCell.innerView.isHidden = false
        } else {
            collectionViewCell.innerView.isHidden = true
        }
        
        return collectionViewCell
    }

}
extension ViewController: UICollectionViewDelegate {
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        for i in (0..<isExpanded.count) {
            if i == indexPath.item {
                // ensure always visible
                isExpanded[i] = true
            } else {
                // set all other rows to false
                isExpanded[i] = false
            }
            if let c = collectionView.cellForItem(at: IndexPath(item: i, section: 0)) as? CollectionViewCell {
                c.innerView.isHidden = !isExpanded[i]
            }
        }
        collectionView.performBatchUpdates(nil, completion: nil)
    }
}

What I have tried so far is

  1. Use a zero height constraint to activate/ deactivate, to replace isHidden
  2. Use UIView.animate

But, the inner UIView will disappear immediately, without any height shrinking animation.

Do you have idea how I can fix this? Thanks.

Here's the code to illustrate the problem - https://github.com/yccheok/shop-dialog/tree/c399bca163096ad27de7de866af5d2de370a8afb

CodePudding user response:

As I mentioned in a comment to you on another question, rarely do we find a "one size fits all" solution.

Instead of fighting with the default behaviors when setting .isHidden on a stack view's arranged subviews, here's a different approach.

Use two bottom constraints:

  • One from the bottom of the "top / always-visible" UI elements
  • One from the bottom of the "show/hide" elements (their container view)

Set the .priority of the second constraint to 750 (.defaultHigh).

When you want the cell to be "collapsed" set the .priority of the first constraint to 751 (.defaultHigh 1).

When you want the cell to be "expanded" set the .priority of the first constraint to 749 (.defaultHigh - 1).

To animate the expand/collapse effect, wrap performBatchUpdates in a UIView.animate block.

I forked your GitHub repo here - https://github.com/DonMag/shop-dialog - and added this approach as "V2" so you can inspect it and see the differences.

  • Related