在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
相关产品推荐
相关产品推荐

