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

React Native自定义下拉刷新动画:蓝点平移实现需求问询

自定义FlatList下拉刷新动画实现方案

效果说明

红色区域为HEADER,蓝色圆点是View或Icon,灰色区域是FlatList列表项;Refresh Control的高度等于HEADER与首个列表项之间的间距。

核心需求

  • 下拉FlatList时,蓝点随下拉距离通过Animated translateX向右移动,最小位移为0,最大位移为WINDOW_WIDTH - BLUE_DOT_WIDTH(即HEADER的中间位置)
  • 初始状态(Refresh Control高度为0)时,蓝点的translateX为0;当下拉到Refresh Control高度达到最大值时,蓝点移动到中间位置并触发刷新
  • 刷新完成后,蓝点停止加载动画,随Refresh Control高度降低向左移动,直到高度归0时回到初始位置(translateX=0)

完整实现代码

import React, { useState, useRef } from 'react';
import { View, FlatList, Animated, StyleSheet, Dimensions, ActivityIndicator } from 'react-native';

// 获取屏幕宽度,定义蓝点尺寸和最大刷新高度
const { width: WINDOW_WIDTH } = Dimensions.get('window');
const BLUE_DOT_WIDTH = 30;
const MAX_REFRESH_HEIGHT = 80;

const CustomRefreshFlatList = () => {
  const [refreshing, setRefreshing] = useState(false);
  // 监听滚动偏移量的动画值
  const scrollY = useRef(new Animated.Value(0)).current;
  // 蓝点的横向位移动画值
  const dotTranslateX = useRef(new Animated.Value(0)).current;

  // 处理滚动事件,实时计算蓝点位移
  const handleScroll = Animated.event(
    [{ nativeEvent: { contentOffset: { y: scrollY } } }],
    {
      useNativeDriver: false,
      listener: (event) => {
        const scrollOffsetY = event.nativeEvent.contentOffset.y;
        // 仅在下拉且未处于刷新状态时计算位移
        if (scrollOffsetY < 0 && !refreshing) {
          const pullDistance = Math.abs(scrollOffsetY);
          // 计算位移比例,限制在0-1区间内
          const ratio = Math.min(pullDistance / MAX_REFRESH_HEIGHT, 1);
          const targetX = ratio * (WINDOW_WIDTH - BLUE_DOT_WIDTH);
          // 实时更新蓝点位置
          Animated.timing(dotTranslateX, {
            toValue: targetX,
            duration: 0,
            useNativeDriver: false,
          }).start();
        }
      },
    }
  );

  // 模拟刷新操作
  const onRefresh = () => {
    setRefreshing(true);
    setTimeout(() => {
      setRefreshing(false);
      // 刷新完成后将蓝点平滑移回初始位置
      Animated.timing(dotTranslateX, {
        toValue: 0,
        duration: 300,
        useNativeDriver: false,
      }).start();
    }, 2000);
  };

  // 自定义刷新控件
  const CustomRefreshControl = () => (
    <View style={styles.refreshContainer}>
      <Animated.View
        style={[
          styles.blueDot,
          { transform: [{ translateX: dotTranslateX }] }
        ]}
      >
        {/* 刷新时显示加载指示器 */}
        {refreshing && <ActivityIndicator color="#ffffff" />}
      </Animated.View>
    </View>
  );

  // 生成模拟列表数据
  const listData = Array.from({ length: 20 }, (_, idx) => ({
    id: idx.toString(),
    label: `列表项 ${idx + 1}`
  }));

  return (
    <View style={styles.container}>
      <View style={styles.header} />
      <FlatList
        data={listData}
        renderItem={({ item }) => (
          <View style={styles.listItem}>
            {/* 可自行添加列表项内容 */}
          </View>
        )}
        keyExtractor={item => item.id}
        onScroll={handleScroll}
        scrollEventThrottle={16} // 保证滚动事件触发频率
        refreshControl={<CustomRefreshControl />}
        onRefresh={onRefresh}
        refreshing={refreshing}
        contentContainerStyle={{ paddingTop: 0 }}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1 },
  header: {
    height: 60,
    backgroundColor: '#ff4444'
  },
  refreshContainer: {
    height: MAX_REFRESH_HEIGHT,
    justifyContent: 'center'
  },
  blueDot: {
    width: BLUE_DOT_WIDTH,
    height: BLUE_DOT_WIDTH,
    borderRadius: BLUE_DOT_WIDTH / 2,
    backgroundColor: '#2196F3',
    justifyContent: 'center',
    alignItems: 'center'
  },
  listItem: {
    height: 60,
    backgroundColor: '#f0f0f0',
    marginVertical: 5,
    marginHorizontal: 10,
    borderRadius: 8
  }
});

export default CustomRefreshFlatList;

内容的提问来源于stack exchange,提问作者SAI

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:05:17