feat: Enhance mobile and tablet support with responsive layout adjustments and new navigation components

This commit is contained in:
zimplexing
2025-08-01 16:36:28 +08:00
parent 942703509e
commit 9e9e4597cc
35 changed files with 4082 additions and 634 deletions

View File

@@ -1,11 +1,13 @@
import React, { useCallback } from "react";
import { View, StyleSheet, ScrollView, Dimensions, ActivityIndicator } from "react-native";
import { View, StyleSheet, ScrollView, ActivityIndicator } from "react-native";
import { ThemedText } from "@/components/ThemedText";
import { useResponsiveLayout } from "@/hooks/useResponsiveLayout";
import { getCommonResponsiveStyles } from "@/utils/ResponsiveStyles";
interface CustomScrollViewProps {
data: any[];
renderItem: ({ item, index }: { item: any; index: number }) => React.ReactNode;
numColumns?: number;
numColumns?: number; // 如果不提供,将使用响应式默认值
loading?: boolean;
loadingMore?: boolean;
error?: string | null;
@@ -15,12 +17,10 @@ interface CustomScrollViewProps {
ListFooterComponent?: React.ComponentType<any> | React.ReactElement | null;
}
const { width } = Dimensions.get("window");
const CustomScrollView: React.FC<CustomScrollViewProps> = ({
data,
renderItem,
numColumns = 1,
numColumns, // 现在可选,如果不提供将使用响应式默认值
loading = false,
loadingMore = false,
error = null,
@@ -29,7 +29,11 @@ const CustomScrollView: React.FC<CustomScrollViewProps> = ({
emptyMessage = "暂无内容",
ListFooterComponent,
}) => {
const ITEM_WIDTH = numColumns > 0 ? width / numColumns - 24 : width - 24;
const responsiveConfig = useResponsiveLayout();
const commonStyles = getCommonResponsiveStyles(responsiveConfig);
// 使用响应式列数,如果没有明确指定的话
const effectiveColumns = numColumns || responsiveConfig.columns;
const handleScroll = useCallback(
({ nativeEvent }: { nativeEvent: any }) => {
@@ -61,7 +65,7 @@ const CustomScrollView: React.FC<CustomScrollViewProps> = ({
if (loading) {
return (
<View style={styles.centerContainer}>
<View style={commonStyles.center}>
<ActivityIndicator size="large" />
</View>
);
@@ -69,8 +73,8 @@ const CustomScrollView: React.FC<CustomScrollViewProps> = ({
if (error) {
return (
<View style={styles.centerContainer}>
<ThemedText type="subtitle" style={{ padding: 10 }}>
<View style={commonStyles.center}>
<ThemedText type="subtitle" style={{ padding: responsiveConfig.spacing }}>
{error}
</ThemedText>
</View>
@@ -79,22 +83,44 @@ const CustomScrollView: React.FC<CustomScrollViewProps> = ({
if (data.length === 0) {
return (
<View style={styles.centerContainer}>
<View style={commonStyles.center}>
<ThemedText>{emptyMessage}</ThemedText>
</View>
);
}
// 动态样式
const dynamicStyles = StyleSheet.create({
listContent: {
paddingBottom: responsiveConfig.spacing * 2,
},
rowContainer: {
flexDirection: "row",
justifyContent: responsiveConfig.deviceType === 'mobile' ? "space-around" : "flex-start",
flexWrap: "wrap",
marginBottom: responsiveConfig.spacing / 2,
},
itemContainer: {
marginHorizontal: responsiveConfig.spacing / 2,
alignItems: "center",
},
});
return (
<ScrollView contentContainerStyle={styles.listContent} onScroll={handleScroll} scrollEventThrottle={16}>
<ScrollView
contentContainerStyle={[commonStyles.gridContainer, dynamicStyles.listContent]}
onScroll={handleScroll}
scrollEventThrottle={16}
showsVerticalScrollIndicator={responsiveConfig.deviceType !== 'tv'}
>
{data.length > 0 ? (
<>
{/* Render content in a grid layout */}
{Array.from({ length: Math.ceil(data.length / numColumns) }).map((_, rowIndex) => (
<View key={rowIndex} style={styles.rowContainer}>
{data.slice(rowIndex * numColumns, (rowIndex + 1) * numColumns).map((item, index) => (
<View key={index} style={[styles.itemContainer, { width: ITEM_WIDTH }]}>
{renderItem({ item, index: rowIndex * numColumns + index })}
{/* Render content in a responsive grid layout */}
{Array.from({ length: Math.ceil(data.length / effectiveColumns) }).map((_, rowIndex) => (
<View key={rowIndex} style={dynamicStyles.rowContainer}>
{data.slice(rowIndex * effectiveColumns, (rowIndex + 1) * effectiveColumns).map((item, index) => (
<View key={index} style={dynamicStyles.itemContainer}>
{renderItem({ item, index: rowIndex * effectiveColumns + index })}
</View>
))}
</View>
@@ -102,34 +128,13 @@ const CustomScrollView: React.FC<CustomScrollViewProps> = ({
{renderFooter()}
</>
) : (
<View style={styles.centerContainer}>
<View style={commonStyles.center}>
<ThemedText>{emptyMessage}</ThemedText>
</View>
)}
</ScrollView>
);
};
const styles = StyleSheet.create({
centerContainer: {
flex: 1,
paddingTop: 20,
justifyContent: "center",
alignItems: "center",
},
listContent: {
paddingHorizontal: 16,
paddingBottom: 20,
},
rowContainer: {
flexDirection: "row",
justifyContent: "flex-start",
flexWrap: "wrap",
},
itemContainer: {
margin: 8,
alignItems: "center",
},
});
export default CustomScrollView;