Custom collection view layout calls prepareLayout after actually asking for the layout

Originator:michaelhochs
Number:rdar://30043880 Date Originated:17-Jan-2017 12:00 AM
Status:3rd party to Resolve Resolved:
Product:iOS Product Version:10.2
Classification:UI/Usability Reproducible:Always
 
Summary:
When implementing a custom collection view layout and invalidating this layout, the collection view calls `-layoutAttributesForElementsInRect:` and after that calls `-prepareLayout`. According to the documentation: “During each layout update, the collection view calls this method first to give your layout object a chance to prepare for the upcoming layout operation.” this should actually be the other way around. The collection view should first let the layout know that it should `-prepareLayout` which would then update the layout to the new truth, and after that, the collection view should ask for this new layout e.g. by calling `-layoutAttributesForElementsInRect:`.

Steps to Reproduce:
- Open the attached sample
- Run this sample in an iPad Air 2 Simulator that launches the app in portrait orientation
- After the initial layout is done, clear the console in Xcode (there are shared breakpoints in the project that log what is called in which order)
- Rotate the device
- Have a look at the console output

Expected Results:
- The layout should adopt the the new width of the view controller
- Console should contain this:
-invalidateLayoutWithContext: 100 indexes
-prepareLayout
-layoutAttributesForElementsInRect: (origin = (x = 0, y = 0), size = (width = 1024, height = 1024))

Actual Results:
- The layout did not update properly
- Console actually contains this:
-invalidateLayoutWithContext: 100 indexes
-layoutAttributesForElementsInRect: (origin = (x = 0, y = 0), size = (width = 1024, height = 1024))
-prepareLayout

Regression:


Notes:
- I tried to make the layout in the sample as small and easy to understand as possible.
- If you launch the app in landscape and rotate to portrait instead, you will see another layout issue where only part of the items updated

Comments

Workaround provided by Apple for the rotation issue

The most straightforward way to handle (workaround) this scenario is to add this code to the host VC:

  • (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [coordinator animateAlongsideTransition:^(id _Nonnull context) { [self.collectionView.collectionViewLayout invalidateLayout]; } completion:nil]; }

which will cause the layout pass that is fired during the rotation event to also include the layout invalidation. There will be 2 invalidation passes.

By michaelhochs at Jan. 18, 2017, 9:17 a.m. (reply...)

Sample Code

https://github.com/PSPDFKit-labs/radar.apple.com/tree/master/30043880%20-%20SimpleCollectionViewLayout

By michaelhochs at Jan. 16, 2017, 11:03 p.m. (reply...)

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!