修复列表长度不够时滑动空白区域无法切换分类问题
This commit is contained in:
@@ -9,7 +9,8 @@ import {
|
|||||||
Dimensions,
|
Dimensions,
|
||||||
Image,
|
Image,
|
||||||
NativeSyntheticEvent,
|
NativeSyntheticEvent,
|
||||||
NativeScrollEvent
|
NativeScrollEvent,
|
||||||
|
LayoutChangeEvent // 导入 LayoutChangeEvent 类型
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
|
|
||||||
const screenWidth = Dimensions.get('window').width;
|
const screenWidth = Dimensions.get('window').width;
|
||||||
@@ -32,7 +33,9 @@ const categoryList = [
|
|||||||
|
|
||||||
// 随机生成游戏数据
|
// 随机生成游戏数据
|
||||||
const generateRandomGames = (categoryId: string, baseName: string) => {
|
const generateRandomGames = (categoryId: string, baseName: string) => {
|
||||||
const count = Math.floor(Math.random() * 11) + 1;
|
// 调整随机数,使其更容易出现空列表或少量item,以测试优化效果
|
||||||
|
// (Math.random() * 6) + 0 意味着可能产生 0 到 5 个
|
||||||
|
const count = Math.floor(Math.random() * 6);
|
||||||
const gameTypes = ['经典版', '豪华版', '至尊版', '竞技版', '休闲版', '大师版', '传奇版', '极速版', '黄金版', '钻石版', '王者版'];
|
const gameTypes = ['经典版', '豪华版', '至尊版', '竞技版', '休闲版', '大师版', '传奇版', '极速版', '黄金版', '钻石版', '王者版'];
|
||||||
const colors = ['4A90E2', 'E94B3C', '50C878', 'F39C12', '9B59B6', 'E74C3C'];
|
const colors = ['4A90E2', 'E94B3C', '50C878', 'F39C12', '9B59B6', 'E74C3C'];
|
||||||
|
|
||||||
@@ -58,6 +61,9 @@ export default function ActivityScreen() {
|
|||||||
const [isSwitching, setIsSwitching] = useState(false);
|
const [isSwitching, setIsSwitching] = useState(false);
|
||||||
const rightListRef = useRef<FlatList>(null);
|
const rightListRef = useRef<FlatList>(null);
|
||||||
|
|
||||||
|
// 【新增】State,用于存储右侧列表容器的实际高度
|
||||||
|
const [rightListHeight, setRightListHeight] = useState(0);
|
||||||
|
|
||||||
// 支持循环切换分类
|
// 支持循环切换分类
|
||||||
const handleCategorySwitch = (direction: 'prev' | 'next') => {
|
const handleCategorySwitch = (direction: 'prev' | 'next') => {
|
||||||
const currentIndex = categoryList.findIndex(item => item.id === selectedId);
|
const currentIndex = categoryList.findIndex(item => item.id === selectedId);
|
||||||
@@ -66,6 +72,7 @@ export default function ActivityScreen() {
|
|||||||
|
|
||||||
// 切换分类
|
// 切换分类
|
||||||
setSelectedId(categoryList[newIndex].id);
|
setSelectedId(categoryList[newIndex].id);
|
||||||
|
// 切换时重置滚动,避免新列表加载时停在奇怪的位置
|
||||||
rightListRef.current?.scrollToOffset({ offset: 0, animated: false });
|
rightListRef.current?.scrollToOffset({ offset: 0, animated: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -76,16 +83,21 @@ export default function ActivityScreen() {
|
|||||||
const layoutHeight = layoutMeasurement.height;
|
const layoutHeight = layoutMeasurement.height;
|
||||||
const contentHeight = contentSize.height;
|
const contentHeight = contentSize.height;
|
||||||
|
|
||||||
|
// 如果正在切换中,则锁定,防止短时间内连续触发
|
||||||
if (isSwitching) return;
|
if (isSwitching) return;
|
||||||
|
|
||||||
// 滑到顶部并继续下拉
|
// 滑到顶部并继续下拉(-40 是一个触发阈值)
|
||||||
if (y < -40) {
|
if (y < -40) {
|
||||||
setIsSwitching(true);
|
setIsSwitching(true);
|
||||||
handleCategorySwitch('prev');
|
handleCategorySwitch('prev');
|
||||||
|
// 延迟重置isSwitching状态,给动画和数据加载留出时间
|
||||||
setTimeout(() => setIsSwitching(false), 600);
|
setTimeout(() => setIsSwitching(false), 600);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 滑到底部并继续上推
|
// 滑到底部并继续上推
|
||||||
|
// contentHeight <= layoutHeight 检查内容是否填满
|
||||||
|
// (如果没填满) y > 40 检查是否在空白处上拉
|
||||||
|
// (如果已填满) y + layoutHeight - contentHeight > 40 检查是否滚动到底部并继续上拉
|
||||||
if (contentHeight <= layoutHeight ? y > 40 : y + layoutHeight - contentHeight > 40) {
|
if (contentHeight <= layoutHeight ? y > 40 : y + layoutHeight - contentHeight > 40) {
|
||||||
setIsSwitching(true);
|
setIsSwitching(true);
|
||||||
handleCategorySwitch('next');
|
handleCategorySwitch('next');
|
||||||
@@ -93,6 +105,14 @@ export default function ActivityScreen() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 【新增】onLayout 事件处理函数
|
||||||
|
// 当右侧容器布局时,获取其高度
|
||||||
|
const onRightListLayout = (event: LayoutChangeEvent) => {
|
||||||
|
const { height } = event.nativeEvent.layout;
|
||||||
|
setRightListHeight(height);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const LeftItem = ({ id, title, icon, isSelected, onPress }: any) => (
|
const LeftItem = ({ id, title, icon, isSelected, onPress }: any) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.leftItem, isSelected && styles.leftItemActive]}
|
style={[styles.leftItem, isSelected && styles.leftItemActive]}
|
||||||
@@ -140,7 +160,10 @@ export default function ActivityScreen() {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* 右侧内容 */}
|
{/* 右侧内容 */}
|
||||||
<View style={styles.contentRight}>
|
{/* 【优化点 1】给容器添加 onLayout 来获取高度 */}
|
||||||
|
<View style={styles.contentRight} onLayout={onRightListLayout}>
|
||||||
|
{/* 只有在获取到高度后才渲染 FlatList,确保 minHeight 初始值正确 */}
|
||||||
|
{rightListHeight > 0 && (
|
||||||
<FlatList
|
<FlatList
|
||||||
ref={rightListRef}
|
ref={rightListRef}
|
||||||
data={mockData[selectedId] || []}
|
data={mockData[selectedId] || []}
|
||||||
@@ -149,11 +172,25 @@ export default function ActivityScreen() {
|
|||||||
)}
|
)}
|
||||||
keyExtractor={item => item.id}
|
keyExtractor={item => item.id}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
|
// bounces 必须为 true (默认值)
|
||||||
bounces={true}
|
bounces={true}
|
||||||
scrollEventThrottle={16}
|
scrollEventThrottle={16}
|
||||||
onScroll={handleScroll}
|
onScroll={handleScroll}
|
||||||
contentContainerStyle={styles.rightListContent}
|
|
||||||
|
// 【优化点 2】为 iOS 添加,使其在内容不足时也能反弹
|
||||||
|
alwaysBounceVertical={true}
|
||||||
|
|
||||||
|
// 【优化点 3】设置 contentContainerStyle
|
||||||
|
contentContainerStyle={[
|
||||||
|
styles.rightListContent,
|
||||||
|
{
|
||||||
|
// 确保内容容器的最小高度
|
||||||
|
// 始终比 FlatList 视图本身高 1 像素
|
||||||
|
minHeight: rightListHeight + 1
|
||||||
|
}
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@@ -194,7 +231,10 @@ const styles = StyleSheet.create({
|
|||||||
borderBottomRightRadius: 2,
|
borderBottomRightRadius: 2,
|
||||||
},
|
},
|
||||||
contentRight: { flex: 1, backgroundColor: '#f5f5f5' },
|
contentRight: { flex: 1, backgroundColor: '#f5f5f5' },
|
||||||
rightListContent: { padding: 12, paddingBottom: 20 },
|
rightListContent: {
|
||||||
|
padding: 12,
|
||||||
|
paddingBottom: 20
|
||||||
|
},
|
||||||
rightItem: {
|
rightItem: {
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
|
|||||||
Reference in New Issue
Block a user