React Native如何实现合作伙伴列表自动无限水平滚动?
React Native实现自动无限水平滚动列表
当然可以实现,下面是基于react-native-animated和ScrollView的完整实现方案,核心思路是通过复制数据源+循环动画+滚动位置重置来实现无限滚动效果:
实现代码
import React, { useEffect, useRef } from 'react'; import { View, ScrollView, Animated, StyleSheet, Image } from 'react-native'; const InfiniteHorizontalScroll = ({ data }) => { // 每个item的固定宽度(含间距) const ITEM_WIDTH = 170; // 150宽度 + 20右边距 const scrollX = useRef(new Animated.Value(0)).current; const scrollViewRef = useRef(null); const isPaused = useRef(false); // 启动循环动画 useEffect(() => { const animateScroll = () => { if (isPaused.current) return; Animated.timing(scrollX, { toValue: data.length * ITEM_WIDTH, duration: data.length * 2000, // 每个item滚动2秒,可自行调整 useNativeDriver: true, }).start(({ finished }) => { if (finished) { // 滚动到末尾后重置位置,实现无缝衔接 scrollX.setValue(0); scrollViewRef.current?.scrollTo({ x: 0, animated: false }); animateScroll(); } }); }; animateScroll(); return () => scrollX.stopAnimation(); }, [data, scrollX]); // 触摸时暂停动画,离开时继续 const handleTouchStart = () => { isPaused.current = true; scrollX.stopAnimation(); }; const handleTouchEnd = () => { isPaused.current = false; // 获取当前滚动位置,继续动画 scrollViewRef.current?.measure((x, y, width, height, pageX, pageY) => { scrollX.setValue(pageX); const remainingDistance = data.length * ITEM_WIDTH - pageX; const remainingDuration = (remainingDistance / (data.length * ITEM_WIDTH)) * (data.length * 2000); Animated.timing(scrollX, { toValue: data.length * ITEM_WIDTH, duration: remainingDuration, useNativeDriver: true, }).start(({ finished }) => { if (finished) { scrollX.setValue(0); scrollViewRef.current?.scrollTo({ x: 0, animated: false }); animateScroll(); } }); }); }; return ( <View style={styles.container}> <Animated.ScrollView ref={scrollViewRef} horizontal showsHorizontalScrollIndicator={false} pagingEnabled={false} contentContainerStyle={styles.scrollContent} onTouchStart={handleTouchStart} onTouchEnd={handleTouchEnd} scrollEventThrottle={16} onScroll={Animated.event( [{ nativeEvent: { contentOffset: { x: scrollX } } }], { useNativeDriver: false } )} > {/* 复制一份数据源,实现无缝衔接 */} {[...data, ...data].map((item, index) => ( <View key={index} style={styles.itemContainer}> <Image source={item.logo} style={styles.logo} resizeMode="contain" /> </View> ))} </Animated.ScrollView> </View> ); }; const styles = StyleSheet.create({ container: { height: 120, marginTop: 20, }, scrollContent: { paddingHorizontal: 10, }, itemContainer: { width: 150, height: 100, marginRight: 20, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f5f5f5', borderRadius: 8, }, logo: { width: '80%', height: '80%', }, }); export default InfiniteHorizontalScroll;
使用方式
你只需要传入合作伙伴的数据源即可,比如:
const partners = [ { logo: require('./assets/partner1.png') }, { logo: require('./assets/partner2.png') }, { logo: require('./assets/partner3.png') }, { logo: require('./assets/partner4.png') }, ]; // 在组件中使用 <InfiniteHorizontalScroll data={partners} />
关键说明
- 数据源复制:通过
[...data, ...data]复制一份列表,确保滚动到原列表末尾时,能衔接上开头的内容,视觉上无断层 - 循环动画控制:用
Animated.timing实现平滑滚动,滚动到末尾后重置滚动位置,触发下一轮动画 - 触摸交互优化:添加触摸暂停/继续逻辑,提升用户体验
- 样式自定义:可根据需求调整
ITEM_WIDTH、动画时长、item样式等参数
内容的提问来源于stack exchange,提问作者Devansh Pant
相关产品推荐
相关产品推荐

