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

在React Native中复刻React项目中的加载Spinner动画

React Native 复刻Web端加载Spinner动画

我在React项目中实现了一个可跨组件复用的加载Spinner,现在正在开发该应用的React Native版本,希望复刻这个加载Spinner。尝试使用react-native的Animated组件来实现,但未能成功,想要实现完全一致的动画效果。原Web端实现代码如下:

Web端实现代码

CSS

.container {
  height: 200px;
  width: 200px;
  position: relative
}

.load {
  position:absolute;
  top:50%;
  left:50%;
  transform:translate(-50%, -50%);
  width:60px;
  height:60px;
}

.loader {
  border:0;
  margin:0;
  width:40%;
  height:40%;
  position:absolute;
  border-radius:50%;
  animation:spin 2s ease infinite
 }

.load1 {
  background:#19A68C;
  animation-delay:-1.5s
}
 
.load2 {
  background:#F63D3A;
  animation-delay:-1s
}

.load3 {
  background:#FDA543;
  animation-delay:-0.5s
}

.load4 {
  background:#193B48
}

@keyframes spin {
  0%,100%{transform:translate(0)}
  25%{transform:translate(160%)}
  50%{transform:translate(160%, 160%)}
  75%{transform:translate(0, 160%)}
}

HTML

<div class="container">
  <div class="load">
    <div class="loader load1"></div>
    <div class="loader load2"></div>
    <div class="loader load3"></div>
    <div class="loader load4"></div>
  </div>
</div>

React Native 实现方案

以下是完全复刻Web端动画效果的React Native组件,使用Animated API实现:

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

const Spinner = () => {
  const anim1 = useRef(new Animated.Value(0)).current;
  const anim2 = useRef(new Animated.Value(0)).current;
  const anim3 = useRef(new Animated.Value(0)).current;
  const anim4 = useRef(new Animated.Value(0)).current;

  const animate = (anim, delay) => {
    Animated.loop(
      Animated.timing(anim, {
        toValue: 1,
        duration: 2000,
        delay: delay,
        useNativeDriver: true,
      })
    ).start();
  };

  useEffect(() => {
    animate(anim1, -1500);
    animate(anim2, -1000);
    animate(anim3, -500);
    animate(anim4, 0);
  }, []);

  const getTransform = (anim) => {
    return anim.interpolate({
      inputRange: [0, 0.25, 0.5, 0.75, 1],
      outputRange: [
        'translate(0, 0)',
        'translate(160%, 0)',
        'translate(160%, 160%)',
        'translate(0, 160%)',
        'translate(0, 0)',
      ],
    });
  };

  return (
    <View style={styles.container}>
      <View style={styles.loadWrapper}>
        <Animated.View style={[styles.loader, styles.load1, { transform: [{ transform: getTransform(anim1) }] }]} />
        <Animated.View style={[styles.loader, styles.load2, { transform: [{ transform: getTransform(anim2) }] }]} />
        <Animated.View style={[styles.loader, styles.load3, { transform: [{ transform: getTransform(anim3) }] }]} />
        <Animated.View style={[styles.loader, styles.load4, { transform: [{ transform: getTransform(anim4) }] }]} />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    width: 200,
    height: 200,
    position: 'relative',
  },
  loadWrapper: {
    position: 'absolute',
    top: '50%',
    left: '50%',
    width: 60,
    height: 60,
    transform: [{ translateX: -30 }, { translateY: -30 }],
  },
  loader: {
    borderWidth: 0,
    margin: 0,
    width: '40%',
    height: '40%',
    position: 'absolute',
    borderRadius: '50%',
  },
  load1: {
    backgroundColor: '#19A68C',
  },
  load2: {
    backgroundColor: '#F63D3A',
  },
  load3: {
    backgroundColor: '#FDA543',
  },
  load4: {
    backgroundColor: '#193B48',
  },
});

export default Spinner;

实现说明

  • 用Animated.loop配合Animated.timing实现无限循环动画,对应Web端infinite属性
  • 通过delay参数设置每个圆形的动画延迟,完全匹配Web端animation-delay的时间差
  • 利用interpolate方法将0-1的动画进度映射为对应平移变换,复刻Web端spin关键帧的四个位置阶段
  • 样式层面对齐Web端的尺寸、定位规则和配色

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:55:07