diff --git a/app/(tabs)/activity.tsx b/app/(tabs)/activity.tsx index a58041b..a6301ab 100644 --- a/app/(tabs)/activity.tsx +++ b/app/(tabs)/activity.tsx @@ -1,10 +1,20 @@ -import React, { useState } from 'react'; -import { ThemedView } from "@/components/themed-view"; -import { Text, SafeAreaView, StyleSheet, View, FlatList, TouchableOpacity, Dimensions, RefreshControl, Image } from "react-native"; +import React, { useState, useRef } from 'react'; +import { + Text, + SafeAreaView, + StyleSheet, + View, + FlatList, + TouchableOpacity, + Dimensions, + Image, + NativeSyntheticEvent, + NativeScrollEvent +} from "react-native"; const screenWidth = Dimensions.get('window').width; -// 分类列表 - 添加图标emoji(扩展到12个) +// 分类列表 const categoryList = [ { id: '0', title: '捕鱼', icon: '🎣' }, { id: '1', title: '真人', icon: '👤' }, @@ -20,107 +30,83 @@ const categoryList = [ { id: '11', title: '其他', icon: '⭐' }, ]; -// 生成随机数量的游戏列表(1-11个) -const generateRandomGames = (categoryId: string, baseName: string): Array<{id: string, name: string, hot: boolean, image: string}> => { - const count = Math.floor(Math.random() * 11) + 1; // 1-11个随机数量 - const games = []; +// 随机生成游戏数据 +const generateRandomGames = (categoryId: string, baseName: string) => { + const count = Math.floor(Math.random() * 11) + 1; const gameTypes = ['经典版', '豪华版', '至尊版', '竞技版', '休闲版', '大师版', '传奇版', '极速版', '黄金版', '钻石版', '王者版']; - - // 模拟图片URL(使用picsum.photos随机图片服务) const colors = ['4A90E2', 'E94B3C', '50C878', 'F39C12', '9B59B6', 'E74C3C']; - - for (let i = 0; i < count; i++) { - const colorIndex = Math.floor(Math.random() * colors.length); - games.push({ - id: `${categoryId}-${i + 1}`, + + return Array.from({ length: count }).map((_, i) => { + const color = colors[Math.floor(Math.random() * colors.length)]; + return { + id: `${categoryId}-${i}`, name: `${baseName}${gameTypes[i % gameTypes.length]}`, - hot: Math.random() > 0.6, // 40%概率为热门 - image: `https://via.placeholder.com/120x80/${colors[colorIndex]}/ffffff?text=Game+${i + 1}`, - }); - } - - return games; + hot: Math.random() > 0.6, + image: `https://via.placeholder.com/120x80/${color}/ffffff?text=Game+${i + 1}`, + }; + }); }; -// 模拟右侧列表数据 - 随机数量(扩展到12个分类) -const mockData: Record> = { - '0': generateRandomGames('0', '捕鱼'), - '1': generateRandomGames('1', '真人百家乐'), - '2': generateRandomGames('2', '链上竞猜'), - '3': generateRandomGames('3', '棋牌对战'), - '4': generateRandomGames('4', '老虎机'), - '5': generateRandomGames('5', '体育竞猜'), - '6': generateRandomGames('6', '彩票'), - '7': generateRandomGames('7', '电竞对战'), - '8': generateRandomGames('8', '赛车竞速'), - '9': generateRandomGames('9', '街机游戏'), - '10': generateRandomGames('10', '桌面游戏'), - '11': generateRandomGames('11', '特色游戏'), -}; - -type LeftItemProps = { - id: string; - title: string; - icon: string; - isSelected: boolean; - onPress: () => void; -}; - -type RightItemProps = { - name: string; - hot: boolean; - image: string; -}; +// 模拟数据 +const mockData: Record> = {}; +categoryList.forEach(cat => { + mockData[cat.id] = generateRandomGames(cat.id, cat.title); +}); export default function ActivityScreen() { const [selectedId, setSelectedId] = useState('0'); - const [refreshingLeft, setRefreshingLeft] = useState(false); - const [refreshingRight, setRefreshingRight] = useState(false); + const [isSwitching, setIsSwitching] = useState(false); + const rightListRef = useRef(null); - // 左侧下拉刷新 - const onRefreshLeft = () => { - setRefreshingLeft(true); - // 模拟刷新延迟 - setTimeout(() => { - setRefreshingLeft(false); - }, 1000); + // 支持循环切换分类 + const handleCategorySwitch = (direction: 'prev' | 'next') => { + const currentIndex = categoryList.findIndex(item => item.id === selectedId); + const total = categoryList.length; + let newIndex = direction === 'next' ? (currentIndex + 1) % total : (currentIndex - 1 + total) % total; + + // 切换分类 + setSelectedId(categoryList[newIndex].id); + rightListRef.current?.scrollToOffset({ offset: 0, animated: false }); }; - // 右侧下拉刷新 - const onRefreshRight = () => { - setRefreshingRight(true); - // 重新生成当前分类的数据 - const categoryNames: Record = { - '0': '捕鱼', '1': '真人百家乐', '2': '链上竞猜', '3': '棋牌对战', - '4': '老虎机', '5': '体育竞猜', '6': '彩票', '7': '电竞对战', - '8': '赛车竞速', '9': '街机游戏', '10': '桌面游戏', '11': '特色游戏' - }; - mockData[selectedId] = generateRandomGames(selectedId, categoryNames[selectedId]); - setTimeout(() => { - setRefreshingRight(false); - }, 1000); + // 实时检测滚动边界 + 循环切换 + const handleScroll = (e: NativeSyntheticEvent) => { + const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent; + const y = contentOffset.y; + const layoutHeight = layoutMeasurement.height; + const contentHeight = contentSize.height; + + if (isSwitching) return; + + // 滑到顶部并继续下拉 + if (y < -40) { + setIsSwitching(true); + handleCategorySwitch('prev'); + setTimeout(() => setIsSwitching(false), 600); + } + + // 滑到底部并继续上推 + if (contentHeight <= layoutHeight ? y > 40 : y + layoutHeight - contentHeight > 40) { + setIsSwitching(true); + handleCategorySwitch('next'); + setTimeout(() => setIsSwitching(false), 600); + } }; - const LeftItem = ({ id, title, icon, isSelected, onPress }: LeftItemProps) => ( - ( + {icon} - - {title} - + {title} {isSelected && } ); - const RightItem = ({ name, hot, image }: RightItemProps) => ( + const RightItem = ({ name, hot, image }: any) => ( - + {name} @@ -133,14 +119,14 @@ export default function ActivityScreen() { return ( - + - {/* 左侧菜单 */} + {/* 左侧分类 */} ( - item.id} showsVerticalScrollIndicator={false} - refreshControl={ - - } /> - {/* 右侧列表 */} + {/* 右侧内容 */} ( )} keyExtractor={item => item.id} showsVerticalScrollIndicator={false} + bounces={true} + scrollEventThrottle={16} + onScroll={handleScroll} contentContainerStyle={styles.rightListContent} - refreshControl={ - - } /> - + ); } const styles = StyleSheet.create({ - safeAreaContainer: { - flex: 1, - backgroundColor: '#f5f5f5', - }, - container: { - flex: 1, - }, - content: { - flex: 1, - flexDirection: 'row', - }, + safeAreaContainer: { flex: 1, backgroundColor: '#f5f5f5' }, + container: { flex: 1 }, + content: { flex: 1, flexDirection: 'row' }, leftWrapper: { width: 90, backgroundColor: '#fff', @@ -212,22 +178,10 @@ const styles = StyleSheet.create({ justifyContent: 'center', position: 'relative', }, - leftItemActive: { - backgroundColor: '#f0f0f0', - }, - leftIcon: { - fontSize: 24, - marginBottom: 4, - }, - leftTitle: { - fontSize: 12, - color: '#666', - textAlign: 'center', - }, - leftTitleActive: { - color: '#1890ff', - fontWeight: '600', - }, + leftItemActive: { backgroundColor: '#f0f0f0' }, + leftIcon: { fontSize: 24, marginBottom: 4 }, + leftTitle: { fontSize: 12, color: '#666', textAlign: 'center' }, + leftTitleActive: { color: '#1890ff', fontWeight: '600' }, activeIndicator: { position: 'absolute', left: 0, @@ -239,13 +193,8 @@ const styles = StyleSheet.create({ borderTopRightRadius: 2, borderBottomRightRadius: 2, }, - contentRight: { - flex: 1, - backgroundColor: '#f5f5f5', - }, - rightListContent: { - padding: 12, - }, + contentRight: { flex: 1, backgroundColor: '#f5f5f5' }, + rightListContent: { padding: 12, paddingBottom: 20 }, rightItem: { backgroundColor: '#fff', borderRadius: 8, @@ -266,35 +215,10 @@ const styles = StyleSheet.create({ marginRight: 12, backgroundColor: '#f0f0f0', }, - rightItemInfo: { - flex: 1, - justifyContent: 'center', - }, - rightItemContent: { - flexDirection: 'row', - alignItems: 'center', - marginBottom: 6, - }, - rightItemTitle: { - fontSize: 15, - fontWeight: '600', - color: '#333', - marginRight: 8, - flex: 1, - }, - hotBadge: { - backgroundColor: '#ff4d4f', - paddingHorizontal: 6, - paddingVertical: 2, - borderRadius: 4, - }, - hotText: { - color: '#fff', - fontSize: 10, - fontWeight: '600', - }, - rightItemDesc: { - fontSize: 13, - color: '#999', - }, -}); \ No newline at end of file + rightItemInfo: { flex: 1, justifyContent: 'center' }, + rightItemContent: { flexDirection: 'row', alignItems: 'center', marginBottom: 6 }, + rightItemTitle: { fontSize: 15, fontWeight: '600', color: '#333', marginRight: 8, flex: 1 }, + hotBadge: { backgroundColor: '#ff4d4f', paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4 }, + hotText: { color: '#fff', fontSize: 10, fontWeight: '600' }, + rightItemDesc: { fontSize: 13, color: '#999' }, +});