1e650bfb3S猫头猫import React, {ReactNode, useEffect, useRef, useState} from 'react'; 2e650bfb3S猫头猫import { 3e650bfb3S猫头猫 LayoutRectangle, 4e650bfb3S猫头猫 StyleSheet, 5e650bfb3S猫头猫 TouchableWithoutFeedback, 6e650bfb3S猫头猫 View, 7e650bfb3S猫头猫 StatusBar as OriginalStatusBar, 8e650bfb3S猫头猫} from 'react-native'; 9e650bfb3S猫头猫import rpx from '@/utils/rpx'; 10e650bfb3S猫头猫import useColors from '@/hooks/useColors'; 11e650bfb3S猫头猫import StatusBar from './statusBar'; 12e650bfb3S猫头猫import color from 'color'; 13e650bfb3S猫头猫import IconButton from './iconButton'; 14e650bfb3S猫头猫import globalStyle from '@/constants/globalStyle'; 15e650bfb3S猫头猫import ThemeText from './themeText'; 16e650bfb3S猫头猫import {useNavigation} from '@react-navigation/native'; 17e650bfb3S猫头猫import Animated, { 18e650bfb3S猫头猫 Easing, 19e650bfb3S猫头猫 useAnimatedStyle, 20e650bfb3S猫头猫 useSharedValue, 21e650bfb3S猫头猫 withTiming, 22e650bfb3S猫头猫} from 'react-native-reanimated'; 23e650bfb3S猫头猫import Portal from './portal'; 24e650bfb3S猫头猫import IconTextButton from './iconTextButton'; 25e650bfb3S猫头猫 26e650bfb3S猫头猫interface IAppBarProps { 27e650bfb3S猫头猫 backgroundOpacity?: number; 28e650bfb3S猫头猫 titleTextOpacity?: number; 29e650bfb3S猫头猫 withStatusBar?: boolean; 30e650bfb3S猫头猫 color?: string; 31e650bfb3S猫头猫 actions?: Array<{ 32e650bfb3S猫头猫 icon: string; 33e650bfb3S猫头猫 onPress?: () => void; 34e650bfb3S猫头猫 }>; 35e650bfb3S猫头猫 menu?: Array<{ 36e650bfb3S猫头猫 icon: string; 37e650bfb3S猫头猫 title: string; 38*7a8d024eS猫头猫 show?: boolean; 39e650bfb3S猫头猫 onPress?: () => void; 40e650bfb3S猫头猫 }>; 41e650bfb3S猫头猫 menuWithStatusBar?: boolean; 42e650bfb3S猫头猫 children?: string | ReactNode; 43e650bfb3S猫头猫} 44e650bfb3S猫头猫 45e650bfb3S猫头猫const ANIMATION_EASING: Animated.EasingFunction = Easing.out(Easing.exp); 46e650bfb3S猫头猫const ANIMATION_DURATION = 500; 47e650bfb3S猫头猫 48e650bfb3S猫头猫const timingConfig = { 49e650bfb3S猫头猫 duration: ANIMATION_DURATION, 50e650bfb3S猫头猫 easing: ANIMATION_EASING, 51e650bfb3S猫头猫}; 52e650bfb3S猫头猫 53e650bfb3S猫头猫export default function AppBar(props: IAppBarProps) { 54e650bfb3S猫头猫 const { 55e650bfb3S猫头猫 backgroundOpacity = 1, 56e650bfb3S猫头猫 titleTextOpacity = 1, 57e650bfb3S猫头猫 withStatusBar, 58e650bfb3S猫头猫 color: _color, 59e650bfb3S猫头猫 actions = [], 60e650bfb3S猫头猫 menu = [], 61e650bfb3S猫头猫 menuWithStatusBar = true, 62e650bfb3S猫头猫 children, 63e650bfb3S猫头猫 } = props; 64e650bfb3S猫头猫 65e650bfb3S猫头猫 const colors = useColors(); 66e650bfb3S猫头猫 const navigation = useNavigation(); 67e650bfb3S猫头猫 68e650bfb3S猫头猫 const bgColor = color(colors.primary).alpha(backgroundOpacity).toString(); 69e650bfb3S猫头猫 const contentColor = _color ?? colors.headerText; 70e650bfb3S猫头猫 71e650bfb3S猫头猫 const [showMenu, setShowMenu] = useState(false); 72e650bfb3S猫头猫 const menuIconLayoutRef = useRef<LayoutRectangle>(); 73e650bfb3S猫头猫 const scaleRate = useSharedValue(0); 74e650bfb3S猫头猫 75e650bfb3S猫头猫 useEffect(() => { 76e650bfb3S猫头猫 if (showMenu) { 77e650bfb3S猫头猫 scaleRate.value = withTiming(1, timingConfig); 78e650bfb3S猫头猫 } else { 79e650bfb3S猫头猫 scaleRate.value = withTiming(0, timingConfig); 80e650bfb3S猫头猫 } 81e650bfb3S猫头猫 }, [showMenu]); 82e650bfb3S猫头猫 83e650bfb3S猫头猫 const transformStyle = useAnimatedStyle(() => { 84e650bfb3S猫头猫 return { 85e650bfb3S猫头猫 opacity: scaleRate.value, 86e650bfb3S猫头猫 }; 87e650bfb3S猫头猫 }); 88e650bfb3S猫头猫 89e650bfb3S猫头猫 return ( 90e650bfb3S猫头猫 <> 91e650bfb3S猫头猫 {withStatusBar ? <StatusBar backgroundColor={bgColor} /> : null} 92e650bfb3S猫头猫 <View style={[styles.container, {backgroundColor: bgColor}]}> 93e650bfb3S猫头猫 <IconButton 94e650bfb3S猫头猫 name="arrow-left" 95e650bfb3S猫头猫 sizeType="normal" 96e650bfb3S猫头猫 color={contentColor} 97e650bfb3S猫头猫 style={globalStyle.notShrink} 98e650bfb3S猫头猫 onPress={() => { 99e650bfb3S猫头猫 navigation.goBack(); 100e650bfb3S猫头猫 }} 101e650bfb3S猫头猫 /> 102e650bfb3S猫头猫 <View style={[globalStyle.grow, styles.content]}> 103e650bfb3S猫头猫 {typeof children === 'string' ? ( 104e650bfb3S猫头猫 <ThemeText 105e650bfb3S猫头猫 fontSize="title" 106e650bfb3S猫头猫 fontWeight="bold" 107e650bfb3S猫头猫 numberOfLines={1} 108e650bfb3S猫头猫 color={ 109e650bfb3S猫头猫 titleTextOpacity !== 1 110e650bfb3S猫头猫 ? color(contentColor) 111e650bfb3S猫头猫 .alpha(titleTextOpacity) 112e650bfb3S猫头猫 .toString() 113e650bfb3S猫头猫 : contentColor 114e650bfb3S猫头猫 }> 115e650bfb3S猫头猫 {children} 116e650bfb3S猫头猫 </ThemeText> 117e650bfb3S猫头猫 ) : ( 118e650bfb3S猫头猫 children 119e650bfb3S猫头猫 )} 120e650bfb3S猫头猫 </View> 121e650bfb3S猫头猫 {actions.map(action => ( 122e650bfb3S猫头猫 <IconButton 123e650bfb3S猫头猫 name={action.icon} 124e650bfb3S猫头猫 sizeType="normal" 125e650bfb3S猫头猫 color={contentColor} 126e650bfb3S猫头猫 style={[globalStyle.notShrink, styles.rightButton]} 127e650bfb3S猫头猫 onPress={action.onPress} 128e650bfb3S猫头猫 /> 129e650bfb3S猫头猫 ))} 130e650bfb3S猫头猫 {menu?.length ? ( 131e650bfb3S猫头猫 <IconButton 132e650bfb3S猫头猫 name="dots-vertical" 133e650bfb3S猫头猫 sizeType="normal" 134e650bfb3S猫头猫 onLayout={e => { 135e650bfb3S猫头猫 menuIconLayoutRef.current = e.nativeEvent.layout; 136e650bfb3S猫头猫 }} 137e650bfb3S猫头猫 color={contentColor} 138e650bfb3S猫头猫 style={[globalStyle.notShrink, styles.rightButton]} 139e650bfb3S猫头猫 onPress={() => { 140e650bfb3S猫头猫 setShowMenu(true); 141e650bfb3S猫头猫 }} 142e650bfb3S猫头猫 /> 143e650bfb3S猫头猫 ) : null} 144e650bfb3S猫头猫 </View> 145e650bfb3S猫头猫 <Portal> 146e650bfb3S猫头猫 {showMenu ? ( 147e650bfb3S猫头猫 <TouchableWithoutFeedback 148e650bfb3S猫头猫 onPress={() => { 149e650bfb3S猫头猫 setShowMenu(false); 150e650bfb3S猫头猫 }}> 151e650bfb3S猫头猫 <View style={styles.blocker} /> 152e650bfb3S猫头猫 </TouchableWithoutFeedback> 153e650bfb3S猫头猫 ) : null} 154e650bfb3S猫头猫 <> 155e650bfb3S猫头猫 <Animated.View 156e650bfb3S猫头猫 pointerEvents={showMenu ? 'auto' : 'none'} 157e650bfb3S猫头猫 style={[ 158e650bfb3S猫头猫 { 159e650bfb3S猫头猫 borderBottomColor: colors.backdrop, 160e650bfb3S猫头猫 left: 161e650bfb3S猫头猫 (menuIconLayoutRef.current?.x ?? 0) + 162e650bfb3S猫头猫 (menuIconLayoutRef.current?.width ?? 0) / 163e650bfb3S猫头猫 2 - 164e650bfb3S猫头猫 rpx(10), 165e650bfb3S猫头猫 top: 166e650bfb3S猫头猫 (menuIconLayoutRef.current?.y ?? 0) + 167e650bfb3S猫头猫 (menuIconLayoutRef.current?.height ?? 0) + 168e650bfb3S猫头猫 (menuWithStatusBar 169e650bfb3S猫头猫 ? OriginalStatusBar.currentHeight ?? 0 170e650bfb3S猫头猫 : 0), 171e650bfb3S猫头猫 }, 172e650bfb3S猫头猫 transformStyle, 173e650bfb3S猫头猫 styles.bubbleCorner, 174e650bfb3S猫头猫 ]} 175e650bfb3S猫头猫 /> 176e650bfb3S猫头猫 <Animated.View 177e650bfb3S猫头猫 pointerEvents={showMenu ? 'auto' : 'none'} 178e650bfb3S猫头猫 style={[ 179e650bfb3S猫头猫 { 180e650bfb3S猫头猫 backgroundColor: colors.headerText, 181e650bfb3S猫头猫 right: rpx(24), 182e650bfb3S猫头猫 top: 183e650bfb3S猫头猫 (menuIconLayoutRef.current?.y ?? 0) + 184e650bfb3S猫头猫 (menuIconLayoutRef.current?.height ?? 0) + 185e650bfb3S猫头猫 rpx(20) + 186e650bfb3S猫头猫 (menuWithStatusBar 187e650bfb3S猫头猫 ? OriginalStatusBar.currentHeight ?? 0 188e650bfb3S猫头猫 : 0), 189e650bfb3S猫头猫 }, 190e650bfb3S猫头猫 transformStyle, 191e650bfb3S猫头猫 styles.menu, 192e650bfb3S猫头猫 ]}> 193*7a8d024eS猫头猫 {menu.map(it => 194*7a8d024eS猫头猫 it.show !== false ? ( 195e650bfb3S猫头猫 <IconTextButton 196e650bfb3S猫头猫 icon={it.icon} 197e650bfb3S猫头猫 onPress={() => { 198e650bfb3S猫头猫 it.onPress?.(); 199e650bfb3S猫头猫 setShowMenu(false); 200e650bfb3S猫头猫 }}> 201e650bfb3S猫头猫 {it.title} 202e650bfb3S猫头猫 </IconTextButton> 203*7a8d024eS猫头猫 ) : null, 204*7a8d024eS猫头猫 )} 205e650bfb3S猫头猫 </Animated.View> 206e650bfb3S猫头猫 </> 207e650bfb3S猫头猫 </Portal> 208e650bfb3S猫头猫 </> 209e650bfb3S猫头猫 ); 210e650bfb3S猫头猫} 211e650bfb3S猫头猫 212e650bfb3S猫头猫const styles = StyleSheet.create({ 213e650bfb3S猫头猫 container: { 214e650bfb3S猫头猫 width: '100%', 215e650bfb3S猫头猫 zIndex: 10000, 216e650bfb3S猫头猫 height: rpx(88), 217e650bfb3S猫头猫 flexDirection: 'row', 218e650bfb3S猫头猫 paddingHorizontal: rpx(24), 219e650bfb3S猫头猫 }, 220e650bfb3S猫头猫 content: { 221e650bfb3S猫头猫 flexDirection: 'row', 222e650bfb3S猫头猫 flexBasis: 0, 223e650bfb3S猫头猫 alignItems: 'center', 224e650bfb3S猫头猫 paddingHorizontal: rpx(24), 225e650bfb3S猫头猫 }, 226e650bfb3S猫头猫 rightButton: { 227e650bfb3S猫头猫 marginLeft: rpx(28), 228e650bfb3S猫头猫 }, 229e650bfb3S猫头猫 blocker: { 230e650bfb3S猫头猫 position: 'absolute', 231e650bfb3S猫头猫 bottom: 0, 232e650bfb3S猫头猫 left: 0, 233e650bfb3S猫头猫 width: '100%', 234e650bfb3S猫头猫 height: '100%', 235e650bfb3S猫头猫 zIndex: 10010, 236e650bfb3S猫头猫 }, 237e650bfb3S猫头猫 bubbleCorner: { 238e650bfb3S猫头猫 position: 'absolute', 239e650bfb3S猫头猫 borderColor: 'transparent', 240e650bfb3S猫头猫 borderWidth: rpx(10), 241e650bfb3S猫头猫 zIndex: 10012, 242e650bfb3S猫头猫 transformOrigin: 'right top', 243e650bfb3S猫头猫 opacity: 0, 244e650bfb3S猫头猫 }, 245e650bfb3S猫头猫 menu: { 246e650bfb3S猫头猫 width: rpx(340), 247e650bfb3S猫头猫 maxHeight: rpx(600), 248e650bfb3S猫头猫 borderRadius: rpx(8), 249e650bfb3S猫头猫 zIndex: 10011, 250e650bfb3S猫头猫 position: 'absolute', 251e650bfb3S猫头猫 opacity: 0, 252e650bfb3S猫头猫 shadowColor: '#000', 253e650bfb3S猫头猫 shadowOffset: { 254e650bfb3S猫头猫 width: 0, 255e650bfb3S猫头猫 height: 2, 256e650bfb3S猫头猫 }, 257e650bfb3S猫头猫 shadowOpacity: 0.23, 258e650bfb3S猫头猫 shadowRadius: 2.62, 259e650bfb3S猫头猫 elevation: 4, 260e650bfb3S猫头猫 }, 261e650bfb3S猫头猫}); 262