diff --git a/FabricExample/package.json b/FabricExample/package.json index 3dbb7d2347..9027ca87c6 100644 --- a/FabricExample/package.json +++ b/FabricExample/package.json @@ -28,7 +28,7 @@ "react": "19.0.0", "react-native": "0.78.0-rc.5", "react-native-gesture-handler": "2.22.0", - "react-native-reanimated": "^4.0.0-nightly-20250218-e5a0cdf69", + "react-native-reanimated": "4.0.0-nightly-20250218-e5a0cdf69", "react-native-restart": "^0.0.27", "react-native-safe-area-context": "5.2.0", "react-native-screens": "link:../" diff --git a/android/src/main/java/com/swmansion/rnscreens/Screen.kt b/android/src/main/java/com/swmansion/rnscreens/Screen.kt index a1e24fd6b0..cdcd19f11d 100644 --- a/android/src/main/java/com/swmansion/rnscreens/Screen.kt +++ b/android/src/main/java/com/swmansion/rnscreens/Screen.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.content.pm.ActivityInfo import android.graphics.Paint import android.os.Parcelable +import android.util.Log import android.util.SparseArray import android.view.MotionEvent import android.view.View @@ -132,6 +133,8 @@ class Screen( ) { val height = bottom - top + Log.i("HT", "Screen [$id] onContentWrapperLayout - $height") + if (usesFormSheetPresentation()) { if (isSheetFitToContents()) { sheetBehavior?.useSingleDetent(height) @@ -139,11 +142,13 @@ class Screen( if (!BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { // On old architecture we delay enter transition in order to wait for initial frame. + Log.i("HT", "Screen [$id] onContentWrapperLayout - request transition trigger") shouldTriggerPostponedTransitionAfterLayout = true val parent = parentAsViewGroup() if (parent != null && !parent.isInLayout) { // There are reported cases (irreproducible) when Screen is not laid out after // maxHeight is set on behaviour. + Log.i("HT", "Screen [$id] onContentWrapperLayout - request parent layout") parent.requestLayout() } } @@ -171,6 +176,7 @@ class Screen( r: Int, b: Int, ) { + Log.i("HT", "Screen [$id] received layout ${b - t}") // In case of form sheet we get layout notification a bit later, in `onBottomSheetBehaviorDidLayout` // after the attached behaviour laid out this view. if (changed && isNativeStackScreen && !usesFormSheetPresentation()) { @@ -193,6 +199,7 @@ class Screen( } footer?.onParentLayout(coordinatorLayoutDidChange, left, top, right, bottom, container!!.height) + Log.i("HT", "Screen [$id] behavior layout") if (!BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { // When using form sheet presentation we want to delay enter transition **on Paper** in order @@ -206,6 +213,7 @@ class Screen( if (shouldTriggerPostponedTransitionAfterLayout) { shouldTriggerPostponedTransitionAfterLayout = false // This will trigger enter transition only if one was requested by ScreenStack + Log.i("HT", "Screen [$id] triggering postponed transition") fragment?.startPostponedEnterTransition() } } @@ -307,6 +315,7 @@ class Screen( throw IllegalStateException("[RNScreens] activityState can only progress in NativeStack") } this.activityState = activityState + Log.i("HT", "Screen [$id] activityState change to $activityState") container?.onChildUpdate() } diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt index d5f940ea91..6a70eb40a8 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt @@ -3,6 +3,7 @@ package com.swmansion.rnscreens import android.content.Context import android.graphics.Canvas import android.os.Build +import android.util.Log import android.view.View import com.facebook.react.bridge.ReactContext import com.facebook.react.uimanager.UIManagerHelper @@ -213,6 +214,7 @@ class ScreenStack( } createTransaction().let { transaction -> + Log.i("HT", "ScreenStack createTransaction") if (stackAnimation != null) { transaction.setTweenAnimations(stackAnimation, shouldUseOpenAnimation) } @@ -226,14 +228,18 @@ class ScreenStack( dismissedWrappers.contains( wrapper, ) - }.forEach { wrapper -> transaction.remove(wrapper.fragment) } + }.forEach { wrapper -> + Log.i("HT", "ScreenStack remove 1 ${wrapper.fragment.id}") + transaction.remove(wrapper.fragment) } // Remove all screens underneath visibleBottom && these marked for preload, but keep newTop. screenWrappers .asSequence() .takeWhile { it !== visibleBottom } .filter { (it !== newTop && !dismissedWrappers.contains(it)) || it.screen.activityState === Screen.ActivityState.INACTIVE } - .forEach { wrapper -> transaction.remove(wrapper.fragment) } + .forEach { wrapper -> + Log.i("HT", "ScreenStack remove 2 ${wrapper.fragment.id}") + transaction.remove(wrapper.fragment) } // attach screens that just became visible if (visibleBottom != null && !visibleBottom.fragment.isAdded) { @@ -243,14 +249,17 @@ class ScreenStack( .dropWhile { it !== visibleBottom } // ignore all screens beneath the visible bottom .forEach { wrapper -> // TODO: It should be enough to dispatch this on commit action once. + Log.i("HT", "ScreenStack add 1 ${wrapper.fragment.id}") transaction.add(id, wrapper.fragment).runOnCommit { top?.screen?.bringToFront() } } } else if (newTop != null && !newTop.fragment.isAdded) { if (newTop.screen.requiresEnterTransitionPostponing()) { + Log.i("HT", "ScreenStack postponeEnterTransition of ${newTop.screen.id}") newTop.fragment.postponeEnterTransition() } + Log.i("HT", "ScreenStack add 2 ${newTop.screen.id}") transaction.add(id, newTop.fragment) } @@ -259,6 +268,7 @@ class ScreenStack( stack.addAll(screenWrappers.asSequence().map { it as ScreenStackFragmentWrapper }) turnOffA11yUnderTransparentScreen(visibleBottom) + Log.i("HT", "ScreenStack commitTransaction") transaction.commitNowAllowingStateLoss() } } diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt index 8b357404d7..3326e2a13f 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt @@ -7,6 +7,7 @@ import android.annotation.SuppressLint import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.Menu import android.view.MenuInflater @@ -285,6 +286,7 @@ class ScreenStackFragment : ValueAnimator.ofObject(evaluator, screen.height.toFloat(), 0f).apply { addUpdateListener { anim -> val animatedValue = anim.animatedValue as? Float + Log.i("HT", "transitionProgress $animatedValue") animatedValue?.let { screen.translationY = it } } } diff --git a/android/src/main/java/com/swmansion/rnscreens/events/ScreenAnimationDelegate.kt b/android/src/main/java/com/swmansion/rnscreens/events/ScreenAnimationDelegate.kt index 34fedac164..bfd1df7187 100644 --- a/android/src/main/java/com/swmansion/rnscreens/events/ScreenAnimationDelegate.kt +++ b/android/src/main/java/com/swmansion/rnscreens/events/ScreenAnimationDelegate.kt @@ -30,6 +30,7 @@ class ScreenAnimationDelegate( override fun onAnimationStart(animation: Animator) { if (currentState === LifecycleState.INITIALIZED) { progressState() + Log.i("HT", "AnimationDelegate onAnimationStart") // These callbacks do not work as expected from this call site, TODO: investigate it. // To fix it quickly we emit required events manually @@ -53,6 +54,7 @@ class ScreenAnimationDelegate( if (currentState === LifecycleState.START_DISPATCHED) { progressState() animation.removeListener(this) + Log.i("HT", "AnimationDelegate onAnimationEnd") // wrapper.onViewAnimationEnd() diff --git a/apps/App.tsx b/apps/App.tsx index 8ed1f92441..0b5c449eb1 100644 --- a/apps/App.tsx +++ b/apps/App.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { enableFreeze } from 'react-native-screens'; -import Example from './Example'; -//import * as Test from './src/tests'; +// import Example from './Example'; +import * as Test from './src/tests'; enableFreeze(true); export default function App() { - return ; - //return ; + // return ; + return ; } diff --git a/apps/src/tests/TestRepro.tsx b/apps/src/tests/TestRepro.tsx new file mode 100644 index 0000000000..7358cc744a --- /dev/null +++ b/apps/src/tests/TestRepro.tsx @@ -0,0 +1,141 @@ +import React from 'react'; +import { NavigationContainer, useNavigation } from '@react-navigation/native'; +import { Button, Text, View } from 'react-native'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; + +const RootStack = createNativeStackNavigator(); +const Tabs = createBottomTabNavigator(); +const TabThreeStack = createNativeStackNavigator(); + +function RootStackHost() { + return ( + + + + + ); +} + +function TabsHost() { + const navigation = useNavigation(); + + React.useEffect(() => { + navigation.preload('RootSheet'); + }, [navigation]); + + return ( + + + + { + return { + tabPress: (event) => { + event.preventDefault(); + navigation.preload('TabThree'); + navigation.navigate('RootSheet'); + }, + }; + }} /> + + ); +} + +function RootHome() { + const navigation = useNavigation(); + + return ( + + RootHome +