Custom supplementary views not positioned correctly by UICollectionViewFlowLayout

Originator:jamesk.au
Number:rdar://30510010 Date Originated:14/02/17
Status:Open Resolved:
Product:iOS + SDK Product Version:iOS 10.2.1 (14D27) and iOS 9.3; Swift 3; Xcode 8.2.1
Classification: Reproducible:Always
 
This bug report has been submitted at the request of Apple Developer Technical Support in response to a Technical Support Incident (follow-up 658037694).

When inserting multiple custom supplementary elements at once in a collection view using a subclass of UICollectionViewFlowLayout, the collection view misplaces some existing custom supplementary views.  This results in unacceptable visual glitches.

The problem does not occur when custom supplementary elements are inserted into an otherwise empty collection view (because, at that stage, there are no existing supplementary views to be misplaced).  Inserting only one supplementary element at a time behaves as expected (for reasons that are unclear).  Inserting two supplementary elements at once results in a visual glitch, and inserting many supplementary elements at once (e.g. 4+) worsens the glitch.

The methods for providing initial and final layout attributes appear to return the correct frames for all supplementary elements for which those attributes are requested.  However, for the existing supplementary views that are misplaced by the collection view, the collection view never requests initial or final layout attributes at all.  Curiously, the calls made by the collection view for initial and final layout attributes for supplementary elements appear to be unbalanced.  That is, initial layout attributes are requested multiple times for the same index path (and, naturally, the same attributes are returned each time), and there are fewer requests for final layout attributes than there are for initial layout attributes.

Items in the collection view are always positioned and animated correctly, even when the layout attributes for those items specify the same frames and index paths as the custom supplementary elements.  The problem appears to be specific to supplementary elements.  (I have not tested decoration elements.)

In my app, I am using a collection view with many items and many supplementary views, and I need to be able to perform animated batch updates reliably without visual artefacts.  I would be grateful for an elegant fix or workaround that does not sacrifice the other functionality provided by a flow layout.

Steps to Reproduce:
The steps to reproduce the issue (all of which have been implemented in the attached example project) are as follows:

1. Create a collection view with a custom subclass of UICollectionViewFlowLayout as its layout object.

2. Create a subclass of UICollectionReusableView to function as a custom supplementary view (being neither a section header nor a section footer).

3. In the flow layout subclass, override and implement the methods necessary to provide layout information for the custom supplementary element, namely:  layoutAttributesForElements(in:), layoutAttributesForSupplementaryView(ofKind:at:), prepare(forCollectionViewUpdates:), indexPathsToInsertForSupplementaryView(ofKind:).

4. Call performBatchUpdates(_:completion:) on the collection view with an update that inserts a sufficient number of items as to require the insertion of multiple custom supplementary elements at once.  (Supplementary elements cannot be inserted directly but are inserted by the layout object in response to the insertion of sections and items.)

5. Observe visual glitches in the presentation of the custom supplementary views. It appears that some existing supplementary views are misplaced or lost, and their presentation is not fixed until the end of the animation block.

Expected Results:
During the insertion of multiple custom supplementary elements, existing and inserted custom supplementary views should be positioned and animated according to the layout attributes provided by the flow layout subclass.

Actual Results:
During the insertion of multiple custom supplementary elements, some existing custom supplementary views are not positioned correctly.

Version:
iOS 10.2.1 (14D27) and iOS 9.3; Swift 3; Xcode 8.2.1

Notes:
The attached example project is available here:  https://github.com/jamesk-au/FlowLayoutInsertionTest

A description of this bug, including screen captures demonstrating the problem, has also been posted on Stack Overflow: http://stackoverflow.com/q/41820776/5352503

The current top-voted answer suggests that UICollectionView may be passing the wrong index paths to collectionView(_:viewForSupplementaryElementOfKind:at:), or is confusing index paths for supplementary elements in some other way.

Configuration:
iPhone 6s 128GB, iOS Simulator (any)

Attachments:
'screen-capture.gif' and 'FlowLayoutInsertionTest-master.zip' were successfully uploaded.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!