import isUndefined from 'lodash/isUndefined'; import React, { useEffect, useRef, useState, memo } from 'react'; import { TouchableOpacity, Animated, BackHandler, StyleSheet, } from 'react-native'; import { getDefaultValue } from '../helpers'; import Theme from '../theme'; import type { OverlayProps } from './interface'; import { varCreator } from './style'; import { useTheme } from '../../components/Theme'; /** * Overlay 遮罩层 * @description 创建一个遮罩层,用于强调特定的页面元素,并阻止用户进行其他操作。 * TODO 统计遮罩层数量,动态控制状态栏的颜色,避免黑色遮罩层配合黑色文字的状态栏。 */ const Overlay: React.FC = ({ children, style, zIndex, visible = false, duration, onPress, onRequestClose, backgroundColor, }) => { const token = useTheme(); const TOKENS = Theme.useThemeTokens(); const CV = Theme.createVar(TOKENS, varCreator); const fadeAnim = useRef(new Animated.Value(0)); const fadeInstance = useRef(null); const [localVisible, setLocalVisible] = useState(visible); duration = getDefaultValue(duration, TOKENS.animation_duration_base); backgroundColor = getDefaultValue(backgroundColor, token['--smegma-1']); // 监听状态变化,执行动画 useEffect(() => { if (visible) { setLocalVisible(true); } fadeInstance.current = Animated.timing( fadeAnim.current, // 动画中的变量值 { toValue: visible ? 1 : 0, duration: duration, useNativeDriver: true, } ); fadeInstance.current.start(({ finished }) => { if (finished) { fadeInstance.current = null; if (!visible) { setLocalVisible(false); } } }); return () => { // 停止动画 if (fadeInstance.current) { fadeInstance.current.stop(); fadeInstance.current = null; } }; }, [visible, duration]); // Android 返回按钮 useEffect(() => { const backHandler = BackHandler.addEventListener( 'hardwareBackPress', () => { if (typeof onRequestClose === 'function' && visible) { return onRequestClose(); } return false; } ); return () => backHandler.remove(); }, [visible, onRequestClose]); if (!localVisible) { // TODO 优化文档报错 // 直接返回 null dumi 报错 -、- return <>; } return ( {children} ); }; const STYLES = StyleSheet.create({ overlay: { position: 'relative', left: 0, right: 0, top: 0, bottom: 0, }, overlay_active: { position: 'absolute', }, touchable: { flex: 1, }, }); export default memo(Overlay);