Fix MVCP anchor selection when z-index reorders children - #57959
Conversation
| paddingBottom?: number, | ||
| }; | ||
|
|
||
| function AppendingList(): React.Node { |
There was a problem hiding this comment.
This change was made because cloneElement seemed to remove the zIndex, so we instead render items without cloneElement.
While I was at it, I also changed this to a function component.
This patch should not be needed once react#57959 is merged. When Fabric reorders scroll content children due to z-index, the old computeTargetView logic picked the first child in hierarchy order whose end position exceeded the scroll offset. That could anchor to the wrong item, so height changes kept the bottom edge fixed instead of the top. Scan all children and select the topmost visible anchor instead. Extend the RNTester AppendingList example with negative z-index values and a "Change height at id" control to reproduce the bug. Test plan (Android): 1. Open RNTester → ScrollView → "smooth bi-directional content loading" 2. Add a few items and scroll so there are items above and below the current item 3. Use "Change height at id" to change the height of an item in the middle 4. Verify the top edge of that item stays in place, rather than the bottom edge jumping Co-authored-by: Cursor <cursoragent@cursor.com>
|
Note that I realized this is an issue on iOS too! I have an idea for a more universal fix that also ensures minIndexForVisible works correctly too (it currently doesn't) |
|
I just updated the PR to also cover iOS and added more automated testing. I then manually retested on both Android and iOS. @janicduplessis I know you wrote the previous PR. Let me know what you think of this one! This is also ready for a review by someone from Meta! @Abbondanzo - it looks like you've reviewed some related logic recently (#57294) - would you maybe be able to review this? I appreciate it! |
| })), | ||
| ); | ||
|
|
||
| const renderItem = (item: ItemInfo, horizontal: boolean) => ( |
There was a problem hiding this comment.
Here's an easier to review diff of the component rendering changes:
When Fabric reorders scroll content children due to z-index, the old computeTargetView logic picked the first child in hierarchy order whose end position exceeded the scroll offset. That could anchor to the wrong item, so height changes kept the bottom edge fixed instead of the top. Scan all children and select the topmost visible anchor instead. Extend the RNTester AppendingList example with negative z-index values and a "Change height at id" control to reproduce the bug. Test plan (Android): 1. Open RNTester → ScrollView → "smooth bi-directional content loading" 2. Add a few items and scroll so there are items above and below the current item 3. Use "Change height at id" to change the height of an item in the middle 4. Verify the top edge of that item stays in place, rather than the bottom edge jumping Co-authored-by: Cursor <cursoragent@cursor.com>
Summary:
Motivation
At Wanderlog, we use a FlatList with negative zIndex so earlier items' bottom shadows can cover later items (by default, later items cover earlier items).
When
maintainVisibleContentPositionis enabled, the native helper selects the scroll anchor by scanning content children and picking the first one whose end position exceeds the current scroll offset. Fabric can reorder native children when views usezIndex, so hierarchy order no longer matches layout order. On both iOS and Android, the helper can then anchor to the wrong item, and scroll corrections keep the bottom edge of the visible content fixed instead of the top.When
minIndexForVisible > 0, skipping early items also needs to follow layout order rather than native hierarchy order.Fix
iOS and Android: Scan all eligible children and select the topmost visible anchor (the smallest end position still below the scroll offset). When
minIndexForVisible > 0, sort children by layout position before applying the skip. Also clear the cached anchor when the helper stops listening.Ported from the approach in #46247, adapted for the current Kotlin helper and Fabric iOS scroll view, and simplified.
Changelog:
[GENERAL] [FIXED] - Fix
maintainVisibleContentPositionanchoring to the wrong child when z-index reorders Fabric childrenTest Plan:
Automated Android tests
Automated Fantom tests
Manual test on iOS and Android using RNTester:
Android
iOS