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

React Native中FlatList多状态动画实现求助:滑入滑出效果

React Native FlatList 多动画效果实现方案

核心解决思路

你遇到的Animated.View只能接收一组transform配置的问题,可以通过合并多个动画的插值结果解决:给每个列表项计算两个独立的动画值(顶部滑出、底部滑入),最终将两者的translateX结果合并为一个总偏移量,赋值给transform数组中的translateX属性。同时单独处理初始加载的滑入动画。

具体实现步骤

1. 初始化动画变量

在组件中创建滚动偏移量动画值、获取屏幕宽度,并定义示例数据:

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

const { width: SCREEN_WIDTH } = Dimensions.get('window');

const AnimatedFlatList = () => {
  // 滚动偏移量动画
  const scrollY = useRef(new Animated.Value(0)).current;
  // 示例列表数据
  const data = Array.from({ length: 20 }).map((_, i) => ({ id: i.toString(), text: `Item ${i + 1}` }));

  return (
    <FlatList
      data={data}
      onScroll={Animated.event(
        [{ nativeEvent: { contentOffset: { y: scrollY } } }],
        { useNativeDriver: true }
      )}
      scrollEventThrottle={16}
      renderItem={({ item, index }) => <AnimatedItem item={item} index={index} scrollY={scrollY} />}
      keyExtractor={item => item.id}
    />
  );
};

2. 自定义动画列表项组件

在列表项中分别计算顶部滑出、底部滑入的动画插值,合并结果后处理初始加载的滑入动画:

const AnimatedItem = ({ item, index, scrollY }) => {
  // 固定项高度(可根据实际需求调整)
  const ITEM_HEIGHT = 80;
  // 初始加载动画值(初始状态为屏幕左侧外)
  const initialAnim = useRef(new Animated.Value(-SCREEN_WIDTH)).current;

  // 初始加载时执行左滑入动画,添加延迟实现 staggered 效果
  useEffect(() => {
    Animated.timing(initialAnim, {
      toValue: 0,
      duration: 500,
      delay: index * 50,
      useNativeDriver: true,
    }).start();
  }, [index, initialAnim]);

  // 计算当前项的上下边界位置
  const itemTop = index * ITEM_HEIGHT;
  const itemBottom = itemTop + ITEM_HEIGHT;

  // 顶部滑出动画:项顶部超出屏幕时,向右滑出
  const topExitAnim = scrollY.interpolate({
    inputRange: [itemTop - ITEM_HEIGHT, itemTop],
    outputRange: [SCREEN_WIDTH, 0],
    extrapolate: 'clamp',
  });

  // 底部滑入动画:项底部进入屏幕时,从左侧滑入
  const bottomEnterAnim = scrollY.interpolate({
    inputRange: [itemBottom - SCREEN_HEIGHT, itemBottom - SCREEN_HEIGHT + ITEM_HEIGHT],
    outputRange: [-SCREEN_WIDTH, 0],
    extrapolate: 'clamp',
  });

  // 合并所有动画:初始动画 + 滚动相关动画
  const finalTranslateX = Animated.add(
    initialAnim,
    Animated.add(topExitAnim, bottomEnterAnim)
  );

  return (
    <Animated.View
      style={[
        styles.item,
        {
          transform: [{ translateX: finalTranslateX }],
        },
      ]}
    >
      <Text style={styles.itemText}>{item.text}</Text>
    </Animated.View>
  );
};

3. 样式补充

const styles = StyleSheet.create({
  item: {
    height: 80,
    padding: 16,
    marginVertical: 8,
    marginHorizontal: 16,
    backgroundColor: '#f0f0f0',
    borderRadius: 8,
    justifyContent: 'center',
  },
  itemText: {
    fontSize: 18,
  },
});

export default AnimatedFlatList;

关键说明

  • 动画合并:通过Animated.add将初始加载动画、顶部滑出动画、底部滑入动画的偏移量相加,最终得到一个总translateX值,让Animated.View只需接收一组transform配置。
  • 插值范围逻辑:
    • 顶部滑出:当滚动偏移量从itemTop - ITEM_HEIGHT到itemTop时,项从完全超出顶部到进入屏幕,对应偏移量从屏幕宽度(完全右滑出)到0(正常位置)。
    • 底部滑入:当滚动偏移量从itemBottom - SCREEN_HEIGHT到itemBottom - SCREEN_HEIGHT + ITEM_HEIGHT时,项从屏幕下方左侧到进入屏幕,对应偏移量从负屏幕宽度(完全左滑出)到0。
  • 初始加载动画:给每个项添加递增延迟,实现依次滑入的视觉效果,可根据需求调整或移除延迟。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 18:48:39