优化歌单详情播放数量显示动画

This commit is contained in:
lyswhut 2023-12-18 14:36:09 +08:00
parent 442c7c6a23
commit 64f128cb55
3 changed files with 89 additions and 15 deletions

View File

@ -3,7 +3,7 @@ import { Text, type TextProps as _TextProps, StyleSheet, Animated, type ColorVal
import { useTheme } from '@/store/theme/hook'
import { setSpText } from '@/utils/pixelRatio'
import { useAnimateColor } from '@/utils/hooks/useAnimateColor'
import { useAnimateNumber } from '@/utils/hooks/useAnimateNumber'
import { DEFAULT_DURATION, useAnimateNumber } from '@/utils/hooks/useAnimateNumber'
// import { AppColors } from '@/theme'
export interface TextProps extends _TextProps {
@ -17,17 +17,50 @@ export interface TextProps extends _TextProps {
color?: ColorValue
}
// const warpText = <P extends TextProps>(Component: ComponentType<TextProps>) => {
// return ({ style, size = 15, color, children, ...props }: P) => {
// const theme = useTheme()
// return (
// <Component
// style={StyleSheet.compose({ fontFamily: 'System', fontSize: setSpText(size), color: color ?? theme['c-font'] }, style)}
// {...props}
// >{children}</Component>
// )
// }
// }
export default ({ style, size = 15, color, children, ...props }: TextProps) => {
const theme = useTheme()
return (
<Text
style={StyleSheet.compose({ fontSize: setSpText(size), color: color ?? theme['c-font'] }, style)}
style={StyleSheet.compose({ fontFamily: 'System', fontSize: setSpText(size), color: color ?? theme['c-font'] }, style)}
{...props}
>{children}</Text>
)
}
export interface AnimatedTextProps extends _AnimatedTextProps {
/**
*
*/
size?: number
/**
*
*/
color?: ColorValue
}
export const AnimatedText = ({ style, size = 15, color, children, ...props }: AnimatedTextProps) => {
const theme = useTheme()
return (
<Animated.Text
style={StyleSheet.compose({ fontFamily: 'System', fontSize: setSpText(size), color: color ?? theme['c-font'] }, style as TextStyle)}
{...props}
>{children}</Animated.Text>
)
}
type _AnimatedTextProps = ComponentProps<(typeof Animated)['Text']>
export interface AnimatedColorTextProps extends _AnimatedTextProps {
@ -48,7 +81,7 @@ export const AnimatedColorText = ({ style, size = 15, opacity: _opacity, color:
const theme = useTheme()
const [color] = useAnimateColor(_color ?? theme['c-font'])
const [opacity] = useAnimateNumber(_opacity ?? 1)
const [opacity] = useAnimateNumber(_opacity ?? 1, DEFAULT_DURATION, false)
return (
<Animated.Text

View File

@ -1,4 +1,4 @@
import { forwardRef, useImperativeHandle, useState } from 'react'
import { forwardRef, memo, useImperativeHandle, useState } from 'react'
import { View } from 'react-native'
import { BorderWidths } from '@/theme'
import ButtonBar from './ActionBar'
@ -6,14 +6,31 @@ import { useNavigationComponentDidAppear } from '@/navigation'
import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant'
import { scaleSizeW } from '@/utils/pixelRatio'
import { useTheme } from '@/store/theme/hook'
import Text from '@/components/common/Text'
import Text, { AnimatedText } from '@/components/common/Text'
import { createStyle } from '@/utils/tools'
import StatusBar from '@/components/common/StatusBar'
import Image from '@/components/common/Image'
import { useListInfo } from './state'
import { useAnimateOnecNumber } from '@/utils/hooks/useAnimateNumber'
const IMAGE_WIDTH = scaleSizeW(70)
const CountText = memo(({ count }: { count: string }) => {
const [animFade] = useAnimateOnecNumber(0, 1, 250, false)
const [animTranslateY] = useAnimateOnecNumber(10, 0, 250, false)
return (
<AnimatedText style={{
...styles.playCount,
opacity: animFade,
transform: [
{ translateY: animTranslateY },
],
}} numberOfLines={ 1 }>{count}</AnimatedText>
)
}, (prevProps, nextProps) => {
return true
})
const Pic = ({ componentId, playCount, imgUrl }: {
componentId: string
playCount: string
@ -28,12 +45,10 @@ const Pic = ({ componentId, playCount, imgUrl }: {
return (
<View style={{ ...styles.listItemImg, width: IMAGE_WIDTH, height: IMAGE_WIDTH }}>
<Image nativeID={`${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${info.id}`} url={imgUrl} style={{ flex: 1, justifyContent: 'flex-end', borderRadius: 4 }} />
{
playCount && animated
? <Text style={styles.playCount} numberOfLines={ 1 }>{playCount}</Text>
: null
}
<Image nativeID={`${NAV_SHEAR_NATIVE_IDS.songlistDetail_pic}_to_${info.id}`} url={imgUrl} style={{ flex: 1, borderRadius: 4 }} />
{
playCount && animated ? <CountText count={playCount} /> : null
}
</View>
)
}
@ -95,6 +110,7 @@ const styles = createStyle({
// backgroundColor: '#eee',
flexGrow: 0,
flexShrink: 0,
overflow: 'hidden',
// width: 70,
// height: 70,
// ...Platform.select({

View File

@ -2,9 +2,9 @@ import { useEffect, useMemo, useRef, useState } from 'react'
import { Animated } from 'react-native'
const ANIMATION_DURATION = 800
export const DEFAULT_DURATION = 800
export const useAnimateNumber = (val: number) => {
export const useAnimateNumber = (val: number, duration = DEFAULT_DURATION, useNativeDriver = true) => {
const anim = useMemo(() => new Animated.Value(0), [val])
const [finished, setFinished] = useState(true)
const currentNumber = useRef(val)
@ -19,8 +19,8 @@ export const useAnimateNumber = (val: number) => {
setFinished(false)
Animated.timing(anim, {
toValue: 1,
duration: ANIMATION_DURATION,
useNativeDriver: false,
duration,
useNativeDriver,
}).start((finished) => {
if (!finished) return
// currentNumber.current = nextNumber
@ -33,3 +33,28 @@ export const useAnimateNumber = (val: number) => {
return [animNumber, finished] as const
}
export const useAnimateOnecNumber = (val: number, toVal: number, duration = DEFAULT_DURATION, useNativeDriver = true) => {
const anim = useMemo(() => new Animated.Value(0), [])
const [finished, setFinished] = useState(true)
const animNumber = anim.interpolate({
inputRange: [0, 1],
outputRange: [val, toVal],
})
useEffect(() => {
setFinished(false)
Animated.timing(anim, {
toValue: 1,
duration,
useNativeDriver,
}).start((finished) => {
if (!finished) return
// currentNumber.current = nextNumber
setFinished(true)
})
}, [])
return [animNumber, finished] as const
}