feat (Android): setTransitionDuration on Android#3698
feat (Android): setTransitionDuration on Android#3698FilPag wants to merge 6 commits intosoftware-mansion:mainfrom
Conversation
|
@kkafar Could you please request reviewers on my behalf. I'm unable to do so :) |
|
Thanks for the tag here. |
There was a problem hiding this comment.
Pull request overview
Adds Android support for configuring native-stack transition duration by plumbing the transitionDuration prop into the Android screen implementation and providing an example UI to tweak durations at runtime.
Changes:
- Switches the
transitionDurationsentinel default to-1(unset) in Fabric codegen specs and the Paper delegate. - Wires
transitionDurationthroughScreenViewManager→Screenand applies it during fragment animation creation. - Extends the Animations example screen with a transition duration picker (via React Navigation
animationDuration).
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/fabric/ScreenNativeComponent.ts | Updates codegen default for transitionDuration to -1 (unset). |
| src/fabric/ModalScreenNativeComponent.ts | Updates codegen default for transitionDuration to -1 (unset). |
| apps/src/screens/Animations.tsx | Adds UI controls to vary transition duration in the example app. |
| android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java | Updates Paper delegate default for transitionDuration to -1. |
| android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt | Implements transitionDuration prop setter for Android screens. |
| android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt | Overrides onCreateAnimation to apply custom duration when set. |
| android/src/main/java/com/swmansion/rnscreens/Screen.kt | Adds transitionDuration field to the Android Screen view. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
# Conflicts: # android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt # android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java
kmichalikk
left a comment
There was a problem hiding this comment.
Hi @FilPag
Thanks for the PR. I left some comments, please answer them.
| var stackPresentation = StackPresentation.PUSH | ||
| var replaceAnimation = ReplaceAnimation.POP | ||
| var stackAnimation = StackAnimation.DEFAULT | ||
| var transitionDuration: Int = -1 |
There was a problem hiding this comment.
nit: Let's document here what does -1 mean or introduce some constant & use it later. If you go for a constant, you might want to make sure that -1 is the only valid negative integer (in the setter, for instance).
| val scale = targetDuration.toDouble() / naturalDuration.toDouble() | ||
| for (child in animation.animations) { | ||
| child.startOffset = (child.startOffset * scale).toLong() | ||
| scaleAnimationDuration(child, (child.duration * scale).toLong()) |
There was a problem hiding this comment.
I think we only have one-level deep nesting in our animations, but still, computeDurationHint for child would be better
| stackPresentation?: CT.WithDefault<StackPresentation, 'push'>; | ||
| stackAnimation?: CT.WithDefault<StackAnimation, 'default'>; | ||
| transitionDuration?: CT.WithDefault<CT.Int32, 500>; | ||
| transitionDuration?: CT.WithDefault<CT.Int32, -1>; |
There was a problem hiding this comment.
You never updated iOS side after this change. It works only because there is a fallback to 500 for duration < 0, but this is not documented anywhere.
There is outdated comment above static constexpr NSTimeInterval RNSDefaultTransitionDuration = 0.5; that you should change.
Additionally, I'd set the above default as soon as possible to not store the negative value anywhere since it's not a valid value in the iOS flow.
| stackPresentation?: CT.WithDefault<StackPresentation, 'push'>; | ||
| stackAnimation?: CT.WithDefault<StackAnimation, 'default'>; | ||
| transitionDuration?: CT.WithDefault<CT.Int32, 500>; | ||
| transitionDuration?: CT.WithDefault<CT.Int32, -1>; |
|
@kmichalikk Thank you for the comments. did some updates. let me know what you think! |
Description
Closes #3694
On iOS, native-stack supports the animationDuration prop, allowing us to make transitions faster. However, on Android, this prop is ignored because the animations are hardcoded in native XML files within react-native-screens. This makes the App feel "laggy" or "unnecessarily heavy" compared to the iOS version or other high-performance native Android apps.
This PR exposes a property to control the transition duration for Android, allowing developers to set a shorter duration (e.g., 200ms instead of the default) to achieve a "snappier" feel.
Changes
Before & after - visual documentation
Screen.Recording.2026-02-26.at.15.26.07.mov
Test plan
Added duration picker to the Animations example screen. Navigate to Animations example screen in FabricExample. Test the duration selector
Checklist