Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionViewFlowLayout edge cells disappear when translation transform is applied

I'm using a custom UICollectionViewFlowLayout to make cells zoom and fade as they reach the top. To do this, I'm applying an alpha and transform to the layout attributes. Here's my code (link to full demo repo):

class EdgeZoomLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let collectionView = collectionView else { return nil }
        let rectAttributes = super.layoutAttributesForElements(in: rect)!.map { $0.copy() as! UICollectionViewLayoutAttributes }
        let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.frame.size)

        for attributes in rectAttributes where attributes.frame.intersects(visibleRect) {
            let positionInFrameY = attributes.center.y - visibleRect.origin.y /// y origin of rectangle
            let cutoff = CGFloat(30)
            
            if positionInFrameY <= cutoff {
                let translation = cutoff - positionInFrameY /// distance from the cutoff, 0 if exactly on cutoff
                let alpha = 1 - (translation / 100)
                let scale = 1 - (translation / 1000)
                
                attributes.alpha = alpha
                attributes.zIndex = Int(alpha >= 1 ? 1 : 0) /// if alpha is 1, keep on the top
                attributes.transform = CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: 0, y: translation)
            } else {
                attributes.zIndex = 1 /// keep on top if not getting zoomed
            }
        }

        return rectAttributes
    }

    /// boilerplate code
    override init() { super.init() }
    required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { return true }
    override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext {
        let context = super.invalidationContext(forBoundsChange: newBounds) as! UICollectionViewFlowLayoutInvalidationContext
        context.invalidateFlowLayoutDelegateMetrics = newBounds.size != collectionView?.bounds.size
        return context
    }
}

This is almost perfect, but the topmost cell disappears suddenly when it gets close to the edge:

Top cell disappears when it reached the top

How can I make the cell zoom and fade without vanishing like that? I think it might be because the collection view recycled the cell... but then, how do I keep it?

like image 468
aheze Avatar asked Oct 24 '25 14:10

aheze


1 Answers

Either you can remove this line

where attributes.frame.intersects(visibleRect)

or you can add some point for visibleRect by this

for attributes in rectAttributes where attributes.frame.intersects(visibleRect.insetBy(dx: 0, dy: -15)) {
like image 177
Raja Kishan Avatar answered Oct 26 '25 05:10

Raja Kishan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!