You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:58:13