React Native实现圆形进度条
React Native实现自定义的圆形进度条动画,主要需要用到Animated和react native svg这个插件。先看看最终实现的效果:

大致思路如下:
1. 使用Svg创建画布,指定画布的宽高;
2. 创建外层倒计时Circle,这里需要使用两个完全重合的Circle叠起来实现,这两个Circle都只保留边框,其中一个Circle显示为进度条背景色(上图中的灰色),另一个Circle显示为进度条的前景色(上图的绿色)。而且由于Svg采用的是渲染叠加图层的方式,所以下层的图形会叠在上层图形之上。因此作为背景的Circle需要放置在上方。
const outerCircleCommonConfig = {fill: 'none', // 填充色为空cx: halfOfSvgSize, // 圆心x坐标值(相对于Svg画布)cy: halfOfSvgSize, // 圆心y坐标值(相对于Svg画布)r: radius, // 圆半径strokeWidth: strokeWidth, // 圆边框宽度strokeDasharray: `${circumference} ${circumference}` // 绘制圆边点划线的图案范式,说白了就是定义虚线的渲染形式,circumference是整个圆的周长
};
上面代码中使用
3. 添加动画属性
const { progress, durationTime } = props;const radian = progress.interpolate({inputRange: [0, 1],outputRange: [0, 2 * Math.PI]});const circumferenceWithProgress = Animated.multiply(radius, radian);const AnimatedCircleProgress = Animated.createAnimatedComponent(Circle);
为了让父级组件能够灵活的控制进度条,所以这里将progress和durationTime(持续时间)定义在父级:
const durationTime = 5; // 持续时间(单位:s)
const [progress, setProgress] = useState(new Animated.Value(0)); // 倒计时动画进度
回到CircleProgress组件中,这里将progress动画值使用interpolate做了一层动画值的映射(插值),我们的进度一般都是[0, 1],而strokeDashOffset偏移量应该是[0, 2 * Math.PI] * radius(弧度 * 半径)范围内。最后为了保证外层Circle的stroke能够“动起来”,需要使用Animated.createAnimatedComponent()方法创建一个能执行动画效果的Circle组件AnimatedCircleProgress。修改后如下:
之后在父级组件中,调用如下方法,修改progress动画值即可。
// 开始倒计时const startCountdown = () => {Animated.timing(progress, {toValue: 1,duration: durationTime * 1000,easing: Easing.linear}).start(() => {});};
如果我们想停止并重置进度条,可以调用如下方法:
const resetCountDown = () => {progress.stopAnimation(); // 停止当前动画progress.setValue(0); // 重置动画值};
4. 添加内层Circle,并显示倒计时时间,还是在CircleProgress组件中:
const [count, setCount] = useState(durationTime);useEffect(() => {progress.addListener(({ value }) => {const ratio = 1 - value;setCount(Math.round(durationTime * ratio));});return () => {progress.removeAllListeners();}}, []);
这里使用progress.addListener监听动画值progress的进度,并计算对应的倒计时的值。然后渲染在Text文本中。
最后我们只需要在父级组件中修改常量durationTime的值就能改变总倒计时时间。非常的方便。
CircleProgress组件完整代码如下:src/components/CirclProgress/index.js文件
/*** 圆形进度条*/
import React, { useState, useEffect } from 'react';
import { Animated } from 'react-native';
import Svg, { Circle, Text, G } from 'react-native-svg';
import { LogUtil } from '@utils';const svgSize = 100; // 画布的宽高
const halfOfSvgSize = svgSize / 2;
const strokeWidth = 2; // 圆形进度条宽度
const radius = (svgSize - strokeWidth) / 2; // 外层倒计时进度半径
const innerRadius = radius - 6; // 内层半径
const circumference = 2 * radius * Math.PI; // 总周长const CircleProgress = (props) => {const { progress, durationTime } = props;const radian = progress.interpolate({inputRange: [0, 1],outputRange: [0, 2 * Math.PI]});const circumferenceWithProgress = Animated.multiply(radius, radian);const AnimatedCircleProgress = Animated.createAnimatedComponent(Circle);const outerCircleCommonConfig = {fill: 'none',cx: halfOfSvgSize,cy: halfOfSvgSize,r: radius,strokeWidth: strokeWidth,strokeDasharray: `${circumference} ${circumference}`};const [count, setCount] = useState(durationTime);useEffect(() => {progress.addListener(({ value }) => {const ratio = 1 - value;setCount(Math.round(durationTime * ratio));});return () => {progress.removeAllListeners();}}, [])return ();
};export default CircleProgress;
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
