// ref: https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/showcase/bottomSheet/index.tsx // When using Model in React Native, the inner FlatList cannot be scrolled. ref: https://zhuanlan.zhihu.com/p/630696822 import * as React from 'react'; import { Animated, GestureResponderEvent, Modal as RNModal, PanResponderGestureState, Platform, StyleSheet, TouchableWithoutFeedback, } from 'react-native'; import { g_mask_color } from '../../const'; import { timeoutTask } from '../../utils'; import { KeyboardAvoidingView } from '../Keyboard'; import { DefaultSlide } from './DefaultSlide'; import { useModalAnimation, useModalPanResponder } from './Modal.hooks'; import type { ModalAnimationType, SlideModalProps, SlideProps } from './types'; /** * Mainly solves the effect problem of native modal component `RNModal` display mask. */ export function SlideModal(props: SlideModalProps) { const { propsRef, modalAnimationType, modalStyle, onRequestModalClose, disableBackgroundClose = false, backgroundColor, backgroundTransparent = false, children, onMoveShouldSetPanResponder, onFinished, Slide, keyboardVerticalOffset, enableSlideComponent = true, enabledKeyboardAdjust = false, ...others } = props; const { translateY, startShow, startHide, backgroundOpacity } = useModalAnimation(modalAnimationType); const [visible, setVisible] = React.useState(false); const SlideWrapper = Slide ?? DefaultSlide; if (propsRef.current) { propsRef.current.startShow = (onf?: () => void, timeout?: number) => { setVisible(true); setTimeout(() => { if (timeout !== undefined) { startShow(() => { timeoutTask(timeout, () => { onf?.(); }); }); } else { startShow(() => { onf?.(); }); } }, 16); // one frame's delay // InteractionManager.runAfterInteractions(() => { // if (timeout !== undefined) { // startShow(() => { // timeoutTask(timeout, () => { // onf?.(); // }); // }); // } else { // startShow(() => { // onf?.(); // }); // } // }); if (timeout !== undefined) { startShow(() => { timeoutTask(timeout, () => { onf?.(); }); }); } else { startShow(() => { onf?.(); }); } }; propsRef.current.startHide = (onf?: () => void, timeout?: number) => { // 使用 InteractionManager 确保动画在主线程执行 // InteractionManager.runAfterInteractions(() => { // if (timeout !== undefined) { // startHide(() => { // // 确保在下一个渲染周期隐藏 Modal // setImmediate(() => { // setVisible(false); // timeoutTask(timeout, () => { // onf?.(); // onFinished?.(); // }); // }); // }); // } else { // startHide(() => { // setImmediate(() => { // setVisible(false); // onf?.(); // onFinished?.(); // }); // }); // } // }); // 先执行动画,不立即隐藏 Modal // if (timeout !== undefined) { // startHide(() => { // // 动画完成后再隐藏 Modal // setTimeout(() => { // setVisible(false); // timeoutTask(timeout, () => { // onf?.(); // onFinished?.(); // }); // }, 50); // 给一点缓冲时间 // }); // } else { // startHide(() => { // // 动画完成后再隐藏 Modal // setTimeout(() => { // setVisible(false); // onf?.(); // onFinished?.(); // }, 50); // }); // } if (timeout !== undefined) { startHide(() => { setVisible(false); timeoutTask(timeout, () => { onf?.(); onFinished?.(); }); }); } else { startHide(() => { setVisible(false); onf?.(); onFinished?.(); }); } }; } // return ( // // {children} // // ); // return ( // // // {children} // // // ); return ( { if (disableBackgroundClose !== true) { onRequestModalClose(); } }} > {/* */} {/* */} {/* // NOTE: https://github.com/facebook/react-native/issues/14295 // Subcomponents need to be wrapped in `Pressable` to support sliding operations. // example: {children} // Note: Nested `FlatList` components are not supported, otherwise the list cannot be scrolled. It is recommended to use the `SimuModal` component. */} {children} {/* {children} */} ); } const SlideComponent = (props: { Slide: | React.ComponentType | ((props: SlideProps) => React.ReactElement); enableSlideComponent: boolean; modalAnimationType: ModalAnimationType; translateY: Animated.Value; startShow: ( callback?: Parameters[0] ) => void; startHide: ( callback?: Parameters[0] ) => void; onRequestModalClose: () => void; onMoveShouldSetPanResponder: | (( e: GestureResponderEvent, gestureState: PanResponderGestureState ) => boolean) | undefined; }) => { const { Slide, modalAnimationType, translateY, startShow, onRequestModalClose, onMoveShouldSetPanResponder, enableSlideComponent, } = props; const panHandlers = useModalPanResponder({ type: modalAnimationType, translateY: translateY, startShow: startShow, onRequestModalClose: onRequestModalClose, onMoveShouldSetPanResponder: onMoveShouldSetPanResponder, }).panHandlers; return enableSlideComponent === true ? ( ) : null; };