import { Image } from 'expo-image'; import React, { useEffect, useRef, useState } from 'react'; import { Animated, Easing, ImageBackground, StyleSheet, Text, View } from 'react-native'; import { Images } from '@/constants/images'; 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; // item.type == '奖池' logic from Vue 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', }, itemBg: { paddingHorizontal: 12, // Reduced padding paddingVertical: 4, marginRight: 10, justifyContent: 'center', height: 32, // Fixed height minWidth: 150, }, contentRow: { flexDirection: 'row', alignItems: 'center', }, avatarBox: { marginRight: 6, width: 24, height: 24, borderRadius: 12, borderWidth: 1, borderColor: '#000', overflow: 'hidden', backgroundColor: '#fff', }, avatar: { width: '100%', height: '100%', }, textContainer: { justifyContent: 'center', }, text: { color: '#fff', fontSize: 10, }, nickname: { fontWeight: 'bold', }, poolName: { color: '#0084FF', fontSize: 10, }, amount: { color: '#FF0000', fontSize: 11, fontWeight: 'bold', } });