From 500e0413fa4dea9feadc80105d2a18327061d57e Mon Sep 17 00:00:00 2001 From: liuhaikang Date: Mon, 17 Nov 2025 17:10:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DScreenContainer=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E5=88=87=E6=8D=A2screens=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liuhaikang --- .../src/components/Screen.tsx | 21 ++++++++++++++++- .../src/components/ScreenContainer.tsx | 23 +++++++++++++++---- react-native-harmony-screens/src/index.ts | 2 +- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/react-native-harmony-screens/src/components/Screen.tsx b/react-native-harmony-screens/src/components/Screen.tsx index 2f5cde4..077b819 100644 --- a/react-native-harmony-screens/src/components/Screen.tsx +++ b/react-native-harmony-screens/src/components/Screen.tsx @@ -13,6 +13,7 @@ import { isNativePlatformSupported, screensEnabled, } from "../core"; +import { ScreenOrderContext } from "./ScreenContainer"; // Native components import ScreenNativeComponent, { @@ -162,6 +163,15 @@ export const InnerScreen = React.forwardRef( const innerRef = React.useRef(null); React.useImperativeHandle(ref, () => innerRef.current!, []); const prevActivityState = usePrevious(props.activityState); + + // RNOH patch: Get declaration order for HarmonyOS only + const isHarmony = (Platform.OS as string) === "harmony"; + const screenOrderContext = isHarmony ? React.useContext(ScreenOrderContext) : null; + const declarationIndexRef = React.useRef(null); + // Initialize synchronously to ensure zIndex is set before first render + if (isHarmony && screenOrderContext && declarationIndexRef.current === null) { + declarationIndexRef.current = screenOrderContext.getNextIndex(); + } const setRef = (ref: ViewConfig) => { innerRef.current = ref; @@ -289,6 +299,15 @@ export const InnerScreen = React.forwardRef( freezeOnBlur && (shouldFreeze !== undefined ? shouldFreeze : activityState === 0); + // RNOH patch: HarmonyOS-specific styles + const harmonyStyle = isHarmony && activityState !== undefined ? { + position: "absolute" as const, + top: 0, left: 0, right: 0, bottom: 0, + opacity: activityState === 0 ? 0 : 1, + pointerEvents: activityState === 0 ? ("none" as const) : activityState === 1 ? ("none" as const) : ("auto" as const), + zIndex: activityState === 0 ? 0 : (declarationIndexRef.current !== null ? declarationIndexRef.current : 1), + } : undefined; + return ( ( // https://github.com/software-mansion/react-native-screens/issues/2345 // With below change of zIndex, we force RN diffing mechanism to NOT include detaching and attaching mutation in one transaction. // Detailed information can be found here https://github.com/software-mansion/react-native-screens/pull/2351 - style={[style, { zIndex: undefined, paddingTop: headerHeight, }]} + style={harmonyStyle ? [style, { paddingTop: headerHeight }, harmonyStyle] : [style, { zIndex: undefined, paddingTop: headerHeight }]} activityState={activityState} sheetAllowedDetents={resolvedSheetAllowedDetents} sheetLargestUndimmedDetent={resolvedSheetLargestUndimmedDetent} diff --git a/react-native-harmony-screens/src/components/ScreenContainer.tsx b/react-native-harmony-screens/src/components/ScreenContainer.tsx index 7dc8c69..73961d9 100644 --- a/react-native-harmony-screens/src/components/ScreenContainer.tsx +++ b/react-native-harmony-screens/src/components/ScreenContainer.tsx @@ -9,8 +9,18 @@ import { isNativePlatformSupported, screensEnabled } from "../core"; import ScreenContainerNativeComponent from "../specs/ScreenContainerNativeComponent"; import ScreenNavigationContainerNativeComponent from "../specs/ScreenNavigationContainerNativeComponent"; +// RNOH patch: Context for HarmonyOS only +const ScreenOrderContext = React.createContext<{ getNextIndex: () => number } | null>(null); + function ScreenContainer(props: ScreenContainerProps) { - const { enabled = screensEnabled(), hasTwoStates, ...rest } = props; + const { enabled = screensEnabled(), hasTwoStates, style, children, ...rest } = props; + const isHarmony = (Platform.OS as string) === "harmony"; + + // RNOH patch: Track declaration order for HarmonyOS only + const screenIndexRef = React.useRef(1); + const getNextIndex = React.useCallback(() => screenIndexRef.current++, []); + React.useEffect(() => { screenIndexRef.current = 1; }, [children]); + const contextValue = React.useMemo(() => ({ getNextIndex }), [getNextIndex]); if (enabled && isNativePlatformSupported) { if (hasTwoStates) { @@ -18,11 +28,16 @@ function ScreenContainer(props: ScreenContainerProps) { Platform.OS === "ios" ? ScreenNavigationContainerNativeComponent : ScreenContainerNativeComponent; - return ; + const container = {children}; + return isHarmony ? {container} : container; } - return ; + const container = {children}; + return isHarmony ? {container} : container; } - return ; + const view = {children}; + return isHarmony ? {view} : view; } +export { ScreenOrderContext }; + export default ScreenContainer; diff --git a/react-native-harmony-screens/src/index.ts b/react-native-harmony-screens/src/index.ts index c02dc60..ff7a30d 100644 --- a/react-native-harmony-screens/src/index.ts +++ b/react-native-harmony-screens/src/index.ts @@ -33,7 +33,7 @@ export { } from "react-native-screens/src/components/ScreenStackHeaderConfig"; export { default as SearchBar } from 'react-native-screens/src/components/SearchBar'; -export { default as ScreenContainer } from 'react-native-screens/src/components/ScreenContainer'; +export { default as ScreenContainer } from './components/ScreenContainer'; export { default as ScreenStack } from './components/ScreenStack'; export { default as ScreenStackItem } from './components/ScreenStackItem'; export { default as FullWindowOverlay } from "react-native-screens/src/components/FullWindowOverlay";