UICollectionViewCell fails to relayout its subviews when UICV layout is invalidated

153 Views Asked by At

I wrote a more detailed blog post on this problem, but here's the gist. I have embedded UICollectionView inside another UIViewController. When the container view changes its bounds, collection view also changes its bounds, which trigger its UICollectionViewLayout to re-layout as well.

All is well except that cells do not re-use new frame and layout using old bounds. This is the log from important methods, where it's obvious that layoutSubviews is using wrong (old) frame.

__57-[RTColumnViewController processCalculatorKeypadVisible:]_block_invoke

-[RTUnitLayout shouldInvalidateLayoutForBoundsChange:] : YES, {{0, 1014}, {272, 375}} -> {{0, 1014}, {175, 375}}
-[RTUnitLayout prepareLayout], bounds={{0, 1014}, {175, 375}}, itemsize={175, 89}
-[RTUnitLayout prepareForAnimatedBoundsChange:] : {{0, 1014}, {272, 375}} -> {{0, 1014}, {175, 375}}

-[RTUnitLayout layoutAttributesForElementsInRect:] : rect={{0, 667}, {175, 1334}}
__50-[RTUnitLayout layoutAttributesForElementsInRect:]_block_invoke_2 : <NSIndexPath: 0xc000000000048016> {length = 2, path = 0 - 9} frame={{0, 801}, {175, 89}}
__50-[RTUnitLayout layoutAttributesForElementsInRect:]_block_invoke_2 : <NSIndexPath: 0xc000000000058016> {length = 2, path = 0 - 11} frame={{0, 979}, {175, 89}}
...

-[RTUnitLayout finalLayoutAttributesForDisappearingItemAtIndexPath:] : <NSIndexPath: 0xc000000000058016> {length = 2, path = 0 - 11} frame={{0, 979}, {272, 89}}
-[RTUnitLayout initialLayoutAttributesForAppearingItemAtIndexPath:] : <NSIndexPath: 0xc000000000058016> {length = 2, path = 0 - 11} frame={{0, 979}, {175, 89}}
-[RTUnitCell layoutSubviews] : pre-super: {{0, 979}, {272, 89}}
-[RTUnitCell layoutSubviews] : post-super: {{0, 979}, {272, 89}}
...

-[RTUnitLayout finalizeAnimatedBoundsChange] : {{0, 1014}, {175, 375}}

__57-[RTColumnViewController processCalculatorKeypadVisible:]_block_invoke623 : completed

After it's done, if I just lightly scroll the UICV, it will trigger re-display and all cells will be shown as they should be. I'm just stumped why this does not happen during the original animation, when it should.

Any ideas..?

1

There are 1 best solutions below

0
On BEST ANSWER

Got back from Apple engineers. If you have custom subclass of UICollectionViewLayoutAttributes, don't make a stupid mistake like I did and return YES form isEqual: method.

It must be:

- (BOOL)isEqual:(id)other {
...
return [super isEqual:other];
}

More details in my blog post.