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