Thursday, August 11, 2022
HomeiOS Developmentios - Why does my Structure constraint on a cells contentView not...

ios – Why does my Structure constraint on a cells contentView not animate?


I attempt to change the scale of a UICollectionViewCells contentView with Auto Structure constraints and it really works however it could actually’t get it to animate. It simply jumps type one constraint to a different.

I discovered that to animate constraint modifications you normally name the next however after I apply that to the contentView it has no impact.

// That is the way you normally animate constraint modifications
myFunctionThatChangesMyConstraints()

UIView.animate(withDuration: 2) {
    layoutIfNeeded()
}

I’m able to animate the cell peak by altering the cell constraints and reapplying a snapshot. I additionally tried that for the contentView but it surely additionally has no impact.

// This works nicely for cell peak however has no impact for contentView peak
myFunctionThatChangesMyConstraints()

UIView.animate(withDuration: 2) {
    self.dataSource.apply(self.dataSource.snapshot(), animatingDifferences: true)
}

Can somebody clarify to me what I am lacking or why it doesn’t work?

Here’s a minimal working instance of the code I exploit:


class CollectionViewController: UIViewController {
    
    enum Part {
        case principal
    }
    
    personal var format: UICollectionViewCompositionalLayout!
    personal var collectionView: UICollectionView!
    personal var dataSource: UICollectionViewDiffableDataSource<Part, Int>!
    
    override func loadView() {
        createLayout()
        createCollectionView()
        createDataSource()
        view = collectionView
    }
    
}


// MARK: - Structure
extension CollectionViewController {
    func createLayout() {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(69))
        let Merchandise = NSCollectionLayoutItem(layoutSize: itemSize)
        
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(300))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [Item])
        
        let part = NSCollectionLayoutSection(group: group)
        
        format = .init(part: part)
    }
    
}

// MARK: - CollectionView
extension CollectionViewController {
    func createCollectionView() {
        collectionView = .init(body: .zero, collectionViewLayout: format)
        
        let doubleTapGestureRecognizer = DoubleTapGestureRecognizer()
        
        doubleTapGestureRecognizer.doubleTapAction = { [unowned self] contact, _ in
            let touchLocation = contact.location(in: collectionView)
            guard let touchedIndexPath = collectionView.indexPathForItem(at: touchLocation) else { return }
            let cell = collectionView.cellForItem(at: touchedIndexPath) as! MyCell
            
            cell.toggleContentHeightConstraint() {
                UIView.animate(withDuration: 2) {
//                    cell.layoutIfNeeded() // <- no impact
//                    self.dataSource.apply(self.dataSource.snapshot(), animatingDifferences: true) // <- additionally no impact
                }
            }
            
//            cell.toggleCellHeightConstraint { // <- works nicely
//                UIView.animate(withDuration: 2) {
//                    self.dataSource.apply(self.dataSource.snapshot(), animatingDifferences: true)
//                }
//            }

        }
        
        collectionView.addGestureRecognizer(doubleTapGestureRecognizer)
        
    }
    
}

// MARK: - DataSource
extension CollectionViewController {
    func createDataSource() {
        let cellRegistration = UICollectionView.CellRegistration<MyCell, Int>() { cell, _, _ in

            cell.contentConfiguration = UIHostingConfiguration {
                MyTextView()
            }
            .background(.orange)
            
            cell.applyConstraints()
            
        }
            
        dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
            return collectionView.dequeueConfiguredReusableCell(utilizing: cellRegistration, for: indexPath, merchandise: itemIdentifier)
        }

        var initialSnapshot = NSDiffableDataSourceSnapshot<Part, Int>()
        initialSnapshot.appendSections([Section.main])
        initialSnapshot.appendItems([0, 1, 2])
        dataSource.applySnapshotUsingReloadData(initialSnapshot)

    }
    
}

class MyCell: UICollectionViewCell {

    var cellHeightConstraint: NSLayoutConstraint!
    var contentHeightConstraint: NSLayoutConstraint!
    
    var selfSizingConstraint: NSLayoutConstraint!
    
    func applyConstraints() {
        contentView.translatesAutoresizingMaskIntoConstraints = false
        
        cellHeightConstraint = heightAnchor.constraint(equalToConstant: 300)
        cellHeightConstraint.precedence = .defaultHigh
        contentHeightConstraint = contentView.heightAnchor.constraint(equalToConstant: 150)
        contentHeightConstraint.precedence = .required
        
        selfSizingConstraint = contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
        selfSizingConstraint.precedence = .defaultLow
        
        NSLayoutConstraint.activate([
            contentView.topAnchor.constraint(equalTo: topAnchor),
            contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
            contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
            selfSizingConstraint,
            contentHeightConstraint,
            cellHeightConstraint
        ])
    }
    
    func toggleContentHeightConstraint(animation: @escaping () -> Void) {
        print("toggle contentHeightConstraint")
        self.contentHeightConstraint.isActive = !self.contentHeightConstraint.isActive // <- the change that doesn't animate
        print("now it is (contentHeightConstraint.isActive)")
        
        animation()
    }
    
    func toggleCellHeightConstraint(animation: @escaping () -> Void) {
        print("toggle cellHeightConstraint")
        cellHeightConstraint.isActive = !cellHeightConstraint.isActive
        print("now it is (cellHeightConstraint.isActive)")
        
        animation()
    }
    
}

class DoubleTapGestureRecognizer: UITapGestureRecognizer {
    var doubleTapAction: ((UITouch, UIEvent) -> Void)?

    override func touchesBegan(_ touches: Set<UITouch>, with occasion: UIEvent) {
        if touches.first!.tapCount == 2 {
            self.doubleTapAction?(touches.first!, occasion)
        }
    }
    
}

struct MyTextView: View {
    
    var physique: some View {
        Textual content("Hiya World! Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim advert minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum")
            .background(.inexperienced)
    }
    
}

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments