Browse Source

首页轮播图指示灯

main
Mac 2 weeks ago
parent
commit
69c7f7f2f7
  1. 278
      app/screens/HomeScreen.tsx

278
app/screens/HomeScreen.tsx

@ -781,6 +781,11 @@ export const HomeScreen = () => {
Alert.alert("已重置", "现在您可以使用相机功能了"); Alert.alert("已重置", "现在您可以使用相机功能了");
}, []); }, []);
// 优化轮播图切换回调
const handleCarouselSnap = useCallback((index: number) => {
setActiveIndex(index);
}, []);
const renderItem = ({ item, index }: { item: Product; index: number }) => { const renderItem = ({ item, index }: { item: Product; index: number }) => {
if (index >= products.length && index < products.length + loadingPlaceholders) { if (index >= products.length && index < products.length + loadingPlaceholders) {
return <ProductSkeleton />; return <ProductSkeleton />;
@ -788,10 +793,11 @@ export const HomeScreen = () => {
return renderProductItem({ item }); return renderProductItem({ item });
}; };
const renderHeader = () => ( const renderHeader = useCallback(() => (
<> <>
<View style={styles.swiperContainer}> <View style={styles.swiperContainer}>
<Carousel <Carousel
key="carousel-header"
width={screenWidth} width={screenWidth}
data={data} data={data}
height={widthUtils(286, 286).height} height={widthUtils(286, 286).height}
@ -799,6 +805,7 @@ export const HomeScreen = () => {
parallaxScrollingScale: 0, parallaxScrollingScale: 0,
parallaxScrollingOffset: 0, parallaxScrollingOffset: 0,
}} }}
onSnapToItem={handleCarouselSnap}
renderItem={({ item }) => ( renderItem={({ item }) => (
<TouchableOpacity <TouchableOpacity
onPress={() => navigation.navigate(item.add)} onPress={() => navigation.navigate(item.add)}
@ -822,6 +829,17 @@ export const HomeScreen = () => {
</TouchableOpacity> </TouchableOpacity>
)} )}
/> />
<View style={styles.indicatorContainer}>
{data.map((_, index) => (
<View
key={index}
style={[
styles.indicator,
index === activeIndex ? styles.activeIndicator : styles.inactiveIndicator,
]}
/>
))}
</View>
<View style={styles.searchOverlay}> <View style={styles.searchOverlay}>
<TouchableOpacity <TouchableOpacity
style={styles.searchBar} style={styles.searchBar}
@ -943,7 +961,7 @@ export const HomeScreen = () => {
</View> </View>
) : null} ) : null}
</> </>
); ), [activeIndex, selectedHorizontalCategory]);
return ( return (
<SafeAreaView style={styles.safeArea}> <SafeAreaView style={styles.safeArea}>
@ -956,30 +974,8 @@ export const HomeScreen = () => {
{renderSkeletonGrid()} {renderSkeletonGrid()}
</View> </View>
) : ( ) : (
<FlatList <ScrollView
ref={flatListRef}
data={[...products, ...Array(loadingPlaceholders).fill(null)]}
numColumns={2}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
columnWrapperStyle={styles.productCardGroup}
renderItem={renderItem}
keyExtractor={(item, index) =>
(item?.offer_id ? `${item.offer_id}-${currentPage}-${index}` : `placeholder-${currentPage}-${index}`)
}
contentContainerStyle={{
paddingBottom: 15,
backgroundColor: "transparent",
}}
ListHeaderComponent={renderHeader}
onEndReached={handleLoadMore}
onEndReachedThreshold={3}
ListFooterComponent={() => (
!hasMore && !loadingPlaceholders ? (
<View style={{ padding: 10, alignItems: 'center' }}>
<Text></Text>
</View>
) : null
)}
refreshControl={ refreshControl={
<RefreshControl <RefreshControl
refreshing={refreshing} refreshing={refreshing}
@ -989,7 +985,236 @@ export const HomeScreen = () => {
progressBackgroundColor="transparent" progressBackgroundColor="transparent"
/> />
} }
/> onScroll={({ nativeEvent }) => {
const { layoutMeasurement, contentOffset, contentSize } = nativeEvent;
const paddingToBottom = 20;
if (layoutMeasurement.height + contentOffset.y >= contentSize.height - paddingToBottom) {
handleLoadMore();
}
}}
scrollEventThrottle={400}
>
{/* 轮播图区域 */}
<View style={styles.swiperContainer}>
<Carousel
key="carousel-header"
width={screenWidth}
data={data}
height={widthUtils(286, 286).height}
modeConfig={{
parallaxScrollingScale: 0,
parallaxScrollingOffset: 0,
}}
onSnapToItem={handleCarouselSnap}
renderItem={({ item }) => (
<TouchableOpacity
onPress={() => navigation.navigate(item.add)}
activeOpacity={1}
key={item.imgUrl}
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#f2f2f2",
borderRadius: 0,
overflow: "hidden",
}}
>
<Image
source={item.imgUrl}
style={{ width: "100%", height: "100%" }}
resizeMode="cover"
defaultSource={require("../../assets/img/banner en (3).png")}
/>
</TouchableOpacity>
)}
/>
<View style={styles.indicatorContainer}>
{data.map((_, index) => (
<View
key={index}
style={[
styles.indicator,
index === activeIndex ? styles.activeIndicator : styles.inactiveIndicator,
]}
/>
))}
</View>
<View style={styles.searchOverlay}>
<TouchableOpacity
style={styles.searchBar}
activeOpacity={0.7}
onPress={navigateToSearch}
>
<IconComponent name="search-outline" size={20} color="#999" />
<Text style={styles.searchPlaceholder}>{t("homePage.searchPlaceholder")}</Text>
<TouchableOpacity
style={styles.cameraButton}
onPress={() => setShowImagePickerModal(true)}
>
<IconComponent name="camera-outline" size={24} color="#333" />
</TouchableOpacity>
</TouchableOpacity>
</View>
</View>
{/* Banner区域 */}
<View style={styles.bannerContainer}>
<View style={styles.leftContainer}>
<TouchableOpacity
style={styles.leftTopItem}
onPress={navigateToShippingDetails}
>
<Image
source={require("../../assets/img/a_计算运费.png")}
style={styles.bannerIcon}
/>
</TouchableOpacity>
<TouchableOpacity
style={styles.leftBottomItem}
onPress={() => navigation.navigate("TikTokScreen")}
>
<Image
source={require("../../assets/img/a_tiktok.png")}
style={styles.bannerIcon}
/>
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.rightContainer}
onPress={navigateToInquiry}
>
<Image
source={require("../../assets/img/a_VIP.png")}
style={styles.bigbannerIcon}
/>
</TouchableOpacity>
</View>
{/* 分类区域 */}
<View style={styles.category}>
<View style={styles.categoryScrollContainer}>
<ScrollView
bounces={false}
overScrollMode="never"
ref={horizontalScrollRef}
horizontal
showsHorizontalScrollIndicator={false}
style={styles.categoryScroll}
>
{categories.map((category, index) => (
<TouchableOpacity
key={index}
style={[
styles.categoryItem,
selectedHorizontalCategory === category && styles.categoryItemActive,
]}
onPress={() => setSelectedHorizontalCategory(category)}
>
<Text
style={[
styles.categoryText,
selectedHorizontalCategory === category && styles.categoryTextActive,
]}
>
{t(`homePage.${category.toLowerCase()}`)}
</Text>
</TouchableOpacity>
))}
</ScrollView>
<LinearGradient
colors={["rgba(255,255,255,0)", "rgba(255,255,255,1)"]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.fadeGradient}
/>
</View>
<View style={styles.categoryArrowContainer}>
<TouchableOpacity onPress={() => setShowCategoryModal(true)}>
<DownArrowIcon size={fontSize(18)} color="#666" rotation={360} />
</TouchableOpacity>
</View>
</View>
{/* 子分类区域 */}
{selectedHorizontalCategory &&
categoryContent[selectedHorizontalCategory] &&
categoryContent[selectedHorizontalCategory].length > 0 ? (
<View style={styles.subcategoryContainer}>
<ScrollView
bounces={false}
overScrollMode="never"
horizontal
showsHorizontalScrollIndicator={false}
style={styles.subcategoryScroll}
contentContainerStyle={styles.subcategoryContent}
>
{categoryContent[selectedHorizontalCategory].map((item) => (
<TouchableOpacity
key={item.id}
style={styles.subcategoryItem}
onPress={() => {
// Handle subcategory selection
}}
>
<View style={styles.subcategoryImagePlaceholder}>
<IconComponent name={item.icon} size={24} color="#666" />
</View>
<Text style={styles.subcategoryText}>{item.title}</Text>
</TouchableOpacity>
))}
</ScrollView>
</View>
) : null}
{/* 产品网格 */}
<View style={styles.productContainer}>
<View style={styles.productCardList}>
{(() => {
const allItems = [...products, ...Array(loadingPlaceholders).fill(null)];
const rows = [];
for (let i = 0; i < allItems.length; i += 2) {
const leftItem = allItems[i];
const rightItem = allItems[i + 1];
rows.push(
<View key={`row-${i}`} style={styles.productCardGroup}>
{/* 左侧商品 */}
{leftItem ? (
i >= products.length ? (
<ProductSkeleton />
) : (
renderProductItem({ item: leftItem })
)
) : null}
{/* 右侧商品 */}
{rightItem ? (
i + 1 >= products.length ? (
<ProductSkeleton />
) : (
renderProductItem({ item: rightItem })
)
) : (
<View style={{ width: "48%" }} />
)}
</View>
);
}
return rows;
})()}
</View>
{/* 底部提示 */}
{!hasMore && !loadingPlaceholders && (
<View style={{ padding: 10, alignItems: 'center' }}>
<Text></Text>
</View>
)}
</View>
</ScrollView>
)} )}
<Modal <Modal
@ -1385,6 +1610,7 @@ const styles = StyleSheet.create<StylesType>({
paddingTop: 0, paddingTop: 0,
}, },
productCardGroup: { productCardGroup: {
flexDirection: "row",
justifyContent: "space-between", justifyContent: "space-between",
marginBottom: 15, marginBottom: 15,
paddingHorizontal: 15, paddingHorizontal: 15,

Loading…
Cancel
Save