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

求助:如何开发带动画的React Native垂直时间线进度条

嘿,我来帮你搞定这个带动画的React Native垂直时间线进度条!先看你附的效果,核心就是要实现进度条的填充动画和节点状态的动态变化对吧?我直接给你拆成可落地的步骤和代码,拿来就能用~

核心思路拆解
  • 先搭基础结构:左侧是垂直的背景线条+动态进度条+状态节点,右侧对应每个节点的文字描述
  • 动画部分分两块:进度条的高度变化动画(随当前进度比例调整),以及节点的缩放/颜色切换动画(标记完成/当前状态)
具体代码实现

我们用React Native自带的Animated API就能搞定,不需要额外装第三方库,先上组件代码:

1. 导入依赖

import React, { useEffect, useRef, useState } from 'react';
import { View, Text, StyleSheet, Animated, Easing, Button } from 'react-native';

2. 定义时间线组件

const TimeLineProgress = ({ currentStep, steps }) => {
  // 用于控制进度条动画的变量
  const progressAnim = useRef(new Animated.Value(0)).current;

  // 当当前步骤变化时,触发进度条动画
  useEffect(() => {
    // 计算当前进度比例:当前步骤数 / 总步骤数
    const progressRatio = currentStep / steps.length;
    Animated.timing(progressAnim, {
      toValue: progressRatio,
      duration: 800, // 动画时长,可自定义
      easing: Easing.out(Easing.ease), // 缓动效果,让动画更自然
      useNativeDriver: false, // 因为要修改height属性,不能用native driver
    }).start();
  }, [currentStep, steps.length]);

  return (
    <View style={styles.container}>
      {/* 左侧时间线区域 */}
      <View style={styles.timelineWrapper}>
        {/* 灰色背景线条 */}
        <View style={styles.timelineBgLine} />
        {/* 动态填充的绿色进度条 */}
        <Animated.View
          style={[
            styles.timelineProgressLine,
            {
              height: progressAnim.interpolate({
                inputRange: [0, 1],
                outputRange: ['0%', '100%'],
              }),
            },
          ]}
        />
        {/* 节点列表 */}
        {steps.map((step, index) => {
          const isCompleted = index < currentStep;
          const isCurrent = index === currentStep;

          return (
            <View key={index} style={styles.nodeWrapper}>
              <Animated.View
                style={[
                  styles.node,
                  {
                    backgroundColor: isCompleted ? '#2ecc71' : isCurrent ? '#3498db' : '#bdc3c7',
                    // 节点完成时的缩放动画
                    transform: [
                      {
                        scale: progressAnim.interpolate({
                          inputRange: [index / steps.length, (index + 1) / steps.length],
                          outputRange: [1, 1.2],
                          extrapolate: 'clamp', // 超出范围保持对应值
                        }),
                      },
                    ],
                  },
                ]}
              />
            </View>
          );
        })}
      </View>

      {/* 右侧步骤文字区域 */}
      <View style={styles.stepsTextWrapper}>
        {steps.map((step, index) => {
          const isCompleted = index < currentStep;
          return (
            <Text
              key={index}
              style={[
                styles.stepText,
                { color: isCompleted ? '#2ecc71' : '#7f8c8d' },
              ]}
            >
              {step.text}
            </Text>
          );
        })}
      </View>
    </View>
  );
};

3. 样式定义

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    alignItems: 'flex-start',
    paddingHorizontal: 20,
    paddingVertical: 10,
    width: '100%',
  },
  timelineWrapper: {
    position: 'relative',
    alignItems: 'center',
    marginRight: 20,
  },
  timelineBgLine: {
    position: 'absolute',
    top: 0,
    bottom: 0,
    width: 2,
    backgroundColor: '#ecf0f1',
  },
  timelineProgressLine: {
    position: 'absolute',
    top: 0,
    width: 2,
    backgroundColor: '#2ecc71',
  },
  nodeWrapper: {
    height: 60, // 每个节点的垂直间距,可根据需求调整
    alignItems: 'center',
    justifyContent: 'center',
  },
  node: {
    width: 16,
    height: 16,
    borderRadius: 8,
    borderWidth: 2,
    borderColor: '#fff',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.2,
    shadowRadius: 2,
    elevation: 2, // Android端阴影效果
  },
  stepsTextWrapper: {
    flex: 1,
    justifyContent: 'space-between',
    height: steps.length * 60, // 和节点高度保持一致
  },
  stepText: {
    fontSize: 14,
    paddingVertical: 18,
    lineHeight: 20,
  },
});

4. 使用示例

// 在你的页面中调用组件
const App = () => {
  const [currentStep, setCurrentStep] = useState(2);
  // 自定义你的步骤数据
  const orderSteps = [
    { text: '订单已创建' },
    { text: '商家已接单' },
    { text: '商品已出库' },
    { text: '正在配送' },
    { text: '已送达' },
  ];

  return (
    <View style={{ flex: 1, justifyContent: 'center', paddingTop: 50 }}>
      <TimeLineProgress currentStep={currentStep} steps={orderSteps} />
      {/* 测试用的按钮,点击切换进度 */}
      <View style={{ marginTop: 30, paddingHorizontal: 20 }}>
        <Button
          title="下一步"
          onPress={() => setCurrentStep(prev => Math.min(prev + 1, orderSteps.length))}
        />
        <Button
          title="上一步"
          onPress={() => setCurrentStep(prev => Math.max(prev - 1, 0))}
          style={{ marginTop: 10 }}
        />
      </View>
    </View>
  );
};
自定义调整小贴士
  • 动画效果:可以修改duration调整动画时长,或者换Easing函数(比如Easing.inOut(Easing.quad))让动画曲线更贴合你的需求
  • 节点样式:如果想把完成的节点换成对勾图标,可以用react-native-vector-icons导入图标组件,替换掉当前的实心圆
  • 进度方向:如果需要进度条从下往上填充,只需要把进度条的position改成bottom,并把interpolate的outputRange改成['100%', '0%']
  • 颜色主题:把代码里的颜色值换成你的设计稿配色就行,比如把完成色改成品牌蓝

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:04:55