fix(Android, Stack v4+): transition RecyclerView as a unit on screen removal - #4555
fix(Android, Stack v4+): transition RecyclerView as a unit on screen removal#4555drhops wants to merge 1 commit into
Conversation
…removal `startTransitionRecursive` marks every descendant of an outgoing screen with `startViewTransition`. RecyclerView owns the attach/detach lifecycle of its children and rejects a holder whose parent is still set, so a ViewPager2 that recycles a page while the exit animation runs crashes with "Scrapped or attached views may not be recycled". Skip recursion into a RecyclerView. It is still marked by its own parent, so the subtree keeps drawing and stays attached; only the per-child marking goes away.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughChangesRecyclerView transition handling
Estimated code review effort: 2 (Simple) | ~5 minutes Merge Risk: ⚪ Minimal · up to This localized Android change adjusts screen-removal transitions and declares the required RecyclerView dependency; no actionable merge-blocking risk remains beyond normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 1 files. (1 skipped: 1 unsupported.)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Fixes an Android native-stack crash by treating RecyclerView as a single transition unit during screen removal.
Changes:
- Stops transition recursion into
RecyclerViewchildren. - Adds an explicit RecyclerView dependency.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
android/src/main/java/com/swmansion/rnscreens/legacy/Screen.kt |
Skips RecyclerView descendants during transition start and end. |
android/build.gradle |
Declares the RecyclerView dependency explicitly. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| implementation 'androidx.fragment:fragment-ktx:1.8.9' | ||
| implementation 'androidx.transition:transition-ktx:1.7.0' | ||
| implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0' | ||
| implementation 'androidx.recyclerview:recyclerview:1.1.0' |
There was a problem hiding this comment.
This is less than perfect and what actually stops me from landing this change.
Additional dependency just for a symbol is a lot.
What's the impact of this on package size?
Also why outdated 1.1.0, when newer versions are available?
There was a problem hiding this comment.
@kkafar this dependency is already included transitively, so this change just makes it direct/explicit given we now rely on it in the code. 1.1.0 because that's what was already being included transitively, and it shouldn't affect package size at all.
Note: this fix was discovered via callstack/react-native-pager-view#1005 (comment) and all credit goes to @mozzius
Description
When a screen is removed,
Screen.startTransitionRecursivecallsstartViewTransitionon every descendant so the outgoing screen keeps drawing through the exit animation. That works by delayingViewGroup's detachment contract and the transitioning view keeps its parent when it is removed:RecyclerViewowns the attach/detach lifecycle of its children, and rejects any holder whose parent is still set:So once a screen removal has marked a
ViewPager2page, the next recycle throws:Repro Steps:
Setup: a RecyclerView inside of a native stack:
<PagerView>is the example in our app.Minimal test screen
On Android: open the pager screen, drag horizontally and release mid-page, then immediately press Back while it's still gliding. Use a back button rather than back gesture. Repeat a couple times given the animation settle window is only a few hundred milliseconds.
Notes
Fixes the crash reported in #2461 (closed without a fix).
Downstream: callstack/react-native-pager-view#1005.
Changes
legacy/Screen.kt: skip recursion into aRecyclerViewinstartTransitionRecursive, and mirrorthe skip in
endTransitionRecursive.android/build.gradle: declareandroidx.recyclerview:recyclerviewexplicitly. It was already onthe compile classpath transitively via Material, but the new import should not rely on that. Pinned
at
1.1.0, which is what Material already resolves.