mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-26 13:35:32 +08:00
fix: add special statusbar handling to modal presentation
This commit is contained in:
@@ -160,6 +160,10 @@ export function forModalPresentationIOS({
|
||||
overflow: 'hidden',
|
||||
borderTopLeftRadius: borderRadius,
|
||||
borderTopRightRadius: borderRadius,
|
||||
// We don't need these for the animation
|
||||
// But different border radius for corners improves animation perf
|
||||
borderBottomLeftRadius: isIphoneX() ? borderRadius : 0,
|
||||
borderBottomRightRadius: isIphoneX() ? borderRadius : 0,
|
||||
marginTop: index === 0 ? 0 : statusBarHeight,
|
||||
marginBottom: index === 0 ? 0 : topOffset,
|
||||
transform: [{ translateY }, { scale }],
|
||||
|
||||
51
packages/stack/src/views/ModalStatusBarManager.tsx
Normal file
51
packages/stack/src/views/ModalStatusBarManager.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import * as React from 'react';
|
||||
import { StatusBar, StyleSheet } from 'react-native';
|
||||
import { useTheme } from '@react-navigation/native';
|
||||
import type { EdgeInsets } from 'react-native-safe-area-context';
|
||||
import type { Layout } from '../types';
|
||||
|
||||
type Props = {
|
||||
layout: Layout;
|
||||
insets: EdgeInsets;
|
||||
style: any;
|
||||
};
|
||||
|
||||
export default function ModalStatusBarManager({
|
||||
layout,
|
||||
insets,
|
||||
style,
|
||||
}: Props) {
|
||||
const { dark } = useTheme();
|
||||
const [isDark, setIsDark] = React.useState(true);
|
||||
|
||||
const flattenedStyle = StyleSheet.flatten(style);
|
||||
const translateY = flattenedStyle?.transform?.find(
|
||||
(s: any) => s.translateY !== undefined
|
||||
)?.translateY;
|
||||
|
||||
React.useEffect(() => {
|
||||
const isLandscape = layout.width > layout.height;
|
||||
const scale = 1 - 20 / layout.width;
|
||||
|
||||
if (dark || isLandscape || !layout.width) {
|
||||
return;
|
||||
}
|
||||
|
||||
const listener = ({ value }: { value: number }) => {
|
||||
const isOverlappingStatusBar = value / scale < insets.top / 3;
|
||||
setIsDark(isOverlappingStatusBar);
|
||||
};
|
||||
|
||||
const sub = translateY?.addListener(listener);
|
||||
|
||||
return () => translateY?.removeListener(sub);
|
||||
}, [dark, insets.top, layout.height, layout.width, translateY]);
|
||||
|
||||
if (dark) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<StatusBar animated barStyle={isDark ? 'dark-content' : 'light-content'} />
|
||||
);
|
||||
}
|
||||
@@ -18,6 +18,8 @@ import {
|
||||
GestureState,
|
||||
PanGestureHandlerGestureEvent,
|
||||
} from '../GestureHandler';
|
||||
import ModalStatusBarManager from '../ModalStatusBarManager';
|
||||
import { forModalPresentationIOS } from '../../TransitionConfigs/CardStyleInterpolators';
|
||||
import CardAnimationContext from '../../utils/CardAnimationContext';
|
||||
import getDistanceForDirection from '../../utils/getDistanceForDirection';
|
||||
import getInvertedMultiplier from '../../utils/getInvertedMultiplier';
|
||||
@@ -523,6 +525,15 @@ export default class Card extends React.Component<Props> {
|
||||
|
||||
return (
|
||||
<CardAnimationContext.Provider value={animationContext}>
|
||||
{index === 0 &&
|
||||
next &&
|
||||
styleInterpolator === forModalPresentationIOS ? (
|
||||
<ModalStatusBarManager
|
||||
layout={layout}
|
||||
insets={insets}
|
||||
style={cardStyle}
|
||||
/>
|
||||
) : null}
|
||||
<Animated.View
|
||||
style={{
|
||||
// This is a dummy style that doesn't actually change anything visually.
|
||||
|
||||
Reference in New Issue
Block a user