import { Colors } from "@/constants/Colors"; import { Image } from "expo-image"; import React, { useEffect, useRef, useState } from "react"; import { Animated, Easing, StyleSheet, Text, View } from "react-native"; interface BarrageItemType { id?: string; poolId?: string; nickname?: string; poolName?: string; text?: string; // amount or feedback type?: string; // '奖池' avatar?: string; } interface BarrageProps { data: BarrageItemType[]; speed?: number; // ms per pixel? Or just a factor. style?: any; } export const Barrage: React.FC = ({ data, speed = 30, style, }) => { const [contentWidth, setContentWidth] = useState(0); const translateX = useRef(new Animated.Value(0)).current; useEffect(() => { if (contentWidth > 0 && data.length > 0) { startAnimation(); } }, [contentWidth, data]); const startAnimation = () => { // Reset to 0 translateX.setValue(0); // Duration: width * factor. // If width is 1000, speed 30 -> 30000ms (30s). const duration = contentWidth * speed; Animated.loop( Animated.timing(translateX, { toValue: -contentWidth, duration: duration, easing: Easing.linear, useNativeDriver: true, }), ).start(); }; const renderItem = (item: BarrageItemType, index: number) => { const isPool = item.poolId && Number(item.text || "0") > 0; return ( {/* Avatar */} {/* Text Content */} {isPool ? ( {item.nickname?.slice(0, 1) + "***" + item.nickname?.slice(-1)} {item.poolName} {item.type === "奖池" ? "消费了" : "获得"} {item.text} {item.type === "奖池" ? "元" : ""} ) : ( {item.nickname?.slice(0, 1) + "***" + item.nickname?.slice(-1)} : {item.text} )} ); }; if (!data || data.length === 0) return null; return ( {/* Measure the width of the first set */} setContentWidth(e.nativeEvent.layout.width)} > {data.map((item, index) => renderItem(item, index))} {/* Duplicate set for seamless loop */} {data.map((item, index) => renderItem(item, index))} ); }; const styles = StyleSheet.create({ container: { width: "100%", overflow: "hidden", height: 40, // Adjust based on item height }, scrollContainer: { flexDirection: "row", }, row: { flexDirection: "row", alignItems: "center", }, itemContainer: { paddingHorizontal: 12, paddingVertical: 4, marginRight: 10, justifyContent: "center", height: 32, minWidth: 150, backgroundColor: "rgba(0, 0, 0, 0.6)", borderRadius: 16, borderWidth: 1, borderColor: "rgba(0, 243, 255, 0.3)", // Neon blue border }, contentRow: { flexDirection: "row", alignItems: "center", }, avatarBox: { marginRight: 6, width: 24, height: 24, borderRadius: 12, borderWidth: 1, borderColor: Colors.neonBlue, overflow: "hidden", backgroundColor: "#000", }, avatar: { width: "100%", height: "100%", }, textContainer: { justifyContent: "center", }, text: { color: Colors.textSecondary, fontSize: 10, }, nickname: { fontWeight: "bold", color: "#fff", }, poolName: { color: Colors.neonBlue, fontSize: 10, }, amount: { color: Colors.neonPink, fontSize: 11, fontWeight: "bold", }, });