Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collection view header flickers when resizing at some values

I have a custom UICollectionView layout that resizes when the user scrolls. As the header shrinks at one point it begins to flicker.

I'm guessing the issue is that when the header shrinks the collection view thinks it's out of frame and perhaps dequeues it but then it calculates that it is in frame and re-queues it which might be what's causing the flicker.

class CustomLayout: UICollectionViewFlowLayout, UICollectionViewDelegateFlowLayout {

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

    let layoutAttributes = super.layoutAttributesForElements(in: rect) as! [UICollectionViewLayoutAttributes]

    let offset = collectionView!.contentOffset ?? CGPoint.zero

    let minY = -sectionInset.top

    if (offset.y >= minY) {

        let setOffset = fabs(170 - minY)
        let extraOffset = fabs(offset.y - minY)

        if  offset.y <= 170 {

            for attributes in  layoutAttributes {
                if let elementKind = attributes.representedElementKind {
                    if elementKind == UICollectionElementKindSectionHeader {

                        var frame = attributes.frame

                        frame.size.height = max(minY, headerReferenceSize.height - (extraOffset * 1.25))
                        frame.origin.y = frame.origin.y + (extraOffset * 1.25)

                        attributes.frame = frame
                    }
                }
            }

        } else {

            for attributes in  layoutAttributes {
                if let elementKind = attributes.representedElementKind {
                    if elementKind == UICollectionElementKindSectionHeader {

                        var frame = attributes.frame

                        frame.size.height = max(minY, headerReferenceSize.height - (setOffset * 1.25))
                        frame.origin.y = frame.origin.y + (setOffset * 1.25)

                        attributes.frame = frame
                    }
                }
            }
        }
    }
    return layoutAttributes
}

override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
    return true
}
}

Here is a gif showing the behavior. Notice how it starts out fine and begins to flicker. Also fast scrolling has an undesired effect.

enter image description here

Any suggestions?

like image 756
Stefan Avatar asked Apr 24 '18 03:04

Stefan


2 Answers

I don't think your issue is related to the layout code. I copied and tried using your CustomLayout in a simple sample app with no obvious flickering issues.

Other things to try:

  1. Make sure your collectionView(viewForSupplementaryElementOfKind:at:) function properly reuses the header view, using collectionView.dequeueReusableSupplementaryView(ofKind:withReuseIdentifier:for:)). Creating a new header view each time could cause substantial delays.
  2. Do you have any complex drawing code in the cell itself?
  3. Worst case, you could try profiling the app using Instruments Time Profiler to see what operations are taking up the most CPU cycles (assuming dropped frames are your issue).
like image 123
cbutton9 Avatar answered Oct 14 '22 08:10

cbutton9


Looks like that your collection view moves the header to the back.

Try insert this in code where you're changing frame of the header:

collectionView.bringSubview(toFront: elementKind)
like image 36
Ivan Smetanin Avatar answered Oct 14 '22 09:10

Ivan Smetanin