fix(mobile): player tab animation (#2918)

This commit is contained in:
Stephen Zhou 2025-03-01 07:34:03 +08:00 committed by GitHub
parent 84b44b3062
commit 7fbd2d7208
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 42 additions and 31 deletions

View File

@ -44,7 +44,7 @@ export const Tabbar: FC<BottomTabBarProps> = (props) => {
return (
<Animated.View
accessibilityRole="tablist"
className="absolute inset-x-0 bottom-0 z-10 py-[7]"
className="absolute inset-x-0 bottom-0 z-10"
style={{
paddingBottom: insets.bottom,
transform: [{ translateY }],
@ -55,7 +55,7 @@ export const Tabbar: FC<BottomTabBarProps> = (props) => {
>
<TabBarBackground />
<PlayerTabBar />
<Grid columns={routes.length} gap={10}>
<Grid columns={routes.length} gap={10} className="mt-[7]">
{routes.map((route, index) => {
const focused = index === state.index
const { options } = descriptors[route.key]!

View File

@ -1,8 +1,14 @@
import { cn } from "@follow/utils"
import { Image } from "expo-image"
import { router, usePathname } from "expo-router"
import { useEffect } from "react"
import { Pressable, Text, View } from "react-native"
import Animated, { SlideInDown, SlideOutDown } from "react-native-reanimated"
import Animated, {
interpolate,
useAnimatedStyle,
useSharedValue,
withTiming,
} from "react-native-reanimated"
import { useActiveTrack } from "@/src/lib/player"
import { usePrefetchImageColors } from "@/src/store/image/hooks"
@ -14,39 +20,44 @@ const allowedRoutes = new Set(["/", "/subscriptions", "/player"])
export function PlayerTabBar({ className }: { className?: string }) {
const activeTrack = useActiveTrack()
const pathname = usePathname()
const isVisible = !!activeTrack && allowedRoutes.has(pathname)
const isVisibleSV = useSharedValue(isVisible ? 1 : 0)
useEffect(() => {
isVisibleSV.value = withTiming(isVisible ? 1 : 0)
}, [pathname, isVisible])
const animatedStyle = useAnimatedStyle(() => {
return {
opacity: isVisibleSV.value,
height: interpolate(isVisibleSV.value, [0, 1], [0, 56]),
overflow: "hidden",
}
})
usePrefetchImageColors(activeTrack?.artwork)
if (!activeTrack || !allowedRoutes.has(pathname)) {
return null
}
return (
<View className="mb-2 overflow-hidden">
<Animated.View
entering={SlideInDown}
exiting={SlideOutDown}
className={cn("border-opaque-separator/70 border-b px-2", className)}
<Animated.View
style={animatedStyle}
className={cn("border-opaque-separator/70 border-b px-2", className)}
>
<Pressable
onPress={() => {
router.push("/player")
}}
>
<Pressable
onPress={() => {
router.push("/player")
}}
>
<View className="flex flex-row items-center gap-4 overflow-hidden rounded-2xl p-2">
<Image source={activeTrack.artwork} className="size-12 rounded-lg" />
<View className="flex-1 overflow-hidden">
<Text className="text-label text-lg font-semibold" numberOfLines={1}>
{activeTrack.title}
</Text>
</View>
<View className="mr-2 flex flex-row gap-4">
<PlayPauseButton />
<SeekButton />
</View>
<View className="flex flex-row items-center gap-4 overflow-hidden rounded-2xl p-2">
<Image source={activeTrack?.artwork} className="size-12 rounded-lg" />
<View className="flex-1 overflow-hidden">
<Text className="text-label text-lg font-semibold" numberOfLines={1}>
{activeTrack?.title ?? ""}
</Text>
</View>
</Pressable>
</Animated.View>
</View>
<View className="mr-2 flex flex-row gap-4">
<PlayPauseButton />
<SeekButton />
</View>
</View>
</Pressable>
</Animated.View>
)
}