feat(Android, Stack v5): allow for native navigation in nested stacks#3601
Merged
feat(Android, Stack v5): allow for native navigation in nested stacks#3601
Conversation
60c9856 to
3807a8a
Compare
c6d235c to
ccae5b7
Compare
This commit refactors *StackContainer* code. Achieved functional effect boils down to support for native-pop in nested stack, and in outer stack after closing the nested one. I've added abstraction over *FragmentManager* operations. This is done mostly to structure and better manage container update code complexity. The *FragmentManager* facing code is now moved into `FragmentOperationExecutor` class. Now *FragmentManager* reference is cleaned up in `onDetachedFromWindow`. The *StackContainer* is now `OnBackStackChangedListener`. This is done to better time & detect that a screen has been dismissed. This callback is invoked mid-transaction execution by fragment manager, not after all animations finish & the UI disappears. It seems like much more appropriate place to keep the *StackContainer* possibly up-to-date. Please note, that *StackScreen* still emits `onDismiss` event much later, after the UI hides & fragment is destroyed. I've changed it a bit here. Earlier it has been emitted in `onDestroyView`, now I emit it in `onDestroy`. I've changed that to prevent incorrect emitting when fragment moves to *STARTED* lifecycle state but is not detached from fragment manager - such situation might happen when we use `FragmentTransaction.detach`, which is planned. This commit also adds basic *primaryNavigationFragment* management. This is necessary for native navigation in nested stacks to work. If we do not set it correctly, then *childFragmentManager* (used by nested stack) won't handle `backPressed` at all. This responsibility will be delegated to the *supportFragmentManager* and whole nested stack will be popped immediately, instead of only single screen. Important thing to note here is that we need to run additional fragment manager operations when we detect that a fragment has been natively popped. `FragmentManager.primaryNavigationFragment` state seems to not be updated automatically once written to, hence unless we update it, we will encounter a crash where *FragmentManager* attempts to delegate back handling to already detached fragment.
ccae5b7 to
5500d7e
Compare
Member
Author
|
Note Do not test this via Example. New stack does not work nicely with v4 implementation, and likely we won't put time into making it work. |
Member
Author
|
This PR uses following patch: diff --git a/FabricExample/android/app/src/main/java/com/fabricexample/MainActivity.kt b/FabricExample/android/app/src/main/java/com/fabricexample/MainActivity.kt
index 145fb50fc..f2863cefb 100644
--- a/FabricExample/android/app/src/main/java/com/fabricexample/MainActivity.kt
+++ b/FabricExample/android/app/src/main/java/com/fabricexample/MainActivity.kt
@@ -25,6 +25,15 @@ class MainActivity : ReactActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
supportFragmentManager.fragmentFactory = RNScreensFragmentFactory()
super.onCreate(savedInstanceState)
+
+ try {
+ val field = ReactActivity::class.java.getDeclaredField("mBackPressedCallback")
+ field.isAccessible = true
+ val callback = field.get(this) as androidx.activity.OnBackPressedCallback
+ callback.isEnabled = false // <--- KILL SWITCH
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
}
override fun onAttachedToWindow() {This makes sure the predictive back gesture to launcher screen works nicely. |
kkafar
commented
Feb 2, 2026
Member
Author
kkafar
left a comment
There was a problem hiding this comment.
I've left some debug logs in the implementation for now intentionally. The implementation will take place for some more time & I don't want to set up all logs for debugging on each PR. This is useful right now & we'll clean it up only after we release alpha / beta version of 5.0.
I've created ticket for that: https://github.com/software-mansion/react-native-screens-labs/issues/925
t0maboro
approved these changes
Feb 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This commit refactors StackContainer code. Achieved functional effect
boils down to support for native-pop in nested stack, and in outer stack
after closing the nested one.
Closes https://github.com/software-mansion/react-native-screens-labs/issues/821
Changes
I've added abstraction over FragmentManager operations. This is done
mostly to structure and better manage container update code complexity.
The FragmentManager facing code is now moved into
FragmentOperationExecutorclass.Now FragmentManager reference is cleaned up in
onDetachedFromWindow.The StackContainer is now
OnBackStackChangedListener. This is doneto better time & detect that a screen has been dismissed. This callback
is invoked mid-transaction execution by fragment manager, not after all
animations finish & the UI disappears. It seems like much more
appropriate place to keep the StackContainer possibly up-to-date.
Please note, that StackScreen still emits
onDismissevent muchlater, after the UI hides & fragment is destroyed. I've changed it a bit
here. Earlier it has been emitted in
onDestroyView, now I emit it inonDestroy. I've changed that to prevent incorrect emitting whenfragment moves to STARTED lifecycle state but is not detached from
fragment manager - such situation might happen when we use
FragmentTransaction.detach, which is planned.This commit also adds basic primaryNavigationFragment management. This
is necessary for native navigation in nested stacks to work. If we do
not set it correctly, then childFragmentManager (used by nested stack)
won't handle
backPressedat all. This responsibility will be delegatedto the supportFragmentManager and whole nested stack will be popped
immediately, instead of only single screen. Important thing to note here
is that we need to run additional fragment manager operations when we
detect that a fragment has been natively popped.
FragmentManager.primaryNavigationFragmentstate seems to not beupdated automatically once written to, hence unless we update it, we
will encounter a crash where FragmentManager attempts to delegate back
handling to already detached fragment.
Visual documentation
Push, Pop, Native pop work nicely, even when popping nested stack. The same action via JS popping should not work yet & will be handled separately.
Screen.Recording.2026-02-02.at.15.38.18.mov
There is no "before" video. This is initial implementation.
Test plan
TestStackNesting
Checklist