React Native中饼图与环形图绘制及填充动画解决方案咨询
在React Native中实现饼图/环形图及填充动画的方案
一、基于你用过的react-native-gifted-charts实现填充动画
这个库本身内置了动画支持,只需配置对应参数即可开启填充动画,环形图也可通过简单参数切换:
animate={true}:启用填充动画animationDuration:自定义动画时长(单位:毫秒)donut:开启环形图模式,donutWidth调整环的宽度
示例代码:
import { PieChart } from 'react-native-gifted-charts'; const chartData = [ {value: 30, color: '#FF6384'}, {value: 50, color: '#36A2EB'}, {value: 20, color: '#FFCE56'}, ]; const AnimatedDonut = () => { return ( <PieChart data={chartData} donut donutWidth={30} animate={true} animationDuration={1500} showValuesAsLabels={true} /> ); }; export default AnimatedDonut;
二、备选库:react-native-chart-kit
该库支持多种图表类型,环形图的填充动画可通过animate参数快速实现,配置灵活:
示例代码:
import { PieChart } from 'react-native-chart-kit'; import { Dimensions } from 'react-native'; const screenWidth = Dimensions.get('window').width; const chartConfig = { color: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`, }; const chartData = [ {name: '分组A', population: 30, color: '#FF6384', legendFontColor: '#333'}, {name: '分组B', population: 50, color: '#36A2EB', legendFontColor: '#333'}, {name: '分组C', population: 20, color: '#FFCE56', legendFontColor: '#333'}, ]; const AnimatedPieChart = () => { return ( <PieChart data={chartData} width={screenWidth} height={220} chartConfig={chartConfig} accessor="population" backgroundColor="transparent" paddingLeft="15" center={[10, 10]} absolute animate animationDuration={1000} donut donutRadius={40} /> ); }; export default AnimatedPieChart;
三、自定义精细动画(基于react-native-svg + Reanimated)
如果需要完全自定义动画节奏或样式,可以用react-native-svg绘制图形,配合react-native-reanimated实现精准的填充动画:
- 先安装依赖:
npm install react-native-svg react-native-reanimated
- 示例代码:
import React, { useEffect } from 'react'; import { View } from 'react-native'; import Svg, { Path } from 'react-native-svg'; import Animated, { useSharedValue, withTiming } from 'react-native-reanimated'; const AnimatedPath = Animated.createAnimatedComponent(Path); const CustomAnimatedDonut = () => { const progress = useSharedValue(0); const totalValue = 100; const data = [30, 50, 20]; const colors = ['#FF6384', '#36A2EB', '#FFCE56']; const radius = 80; const donutWidth = 25; const centerX = radius + donutWidth; const centerY = radius + donutWidth; // 计算扇形路径 const getArcPath = (startAngle, endAngle) => { const startRadians = (startAngle * Math.PI) / 180; const endRadians = (endAngle * Math.PI) / 180; const largeArcFlag = endAngle - startAngle > 180 ? 1 : 0; const x1 = centerX + radius * Math.cos(startRadians); const y1 = centerY + radius * Math.sin(startRadians); const x2 = centerX + radius * Math.cos(endRadians); const y2 = centerY + radius * Math.sin(endRadians); const innerRadius = radius - donutWidth; const x1Inner = centerX + innerRadius * Math.cos(startRadians); const y1Inner = centerY + innerRadius * Math.sin(startRadians); const x2Inner = centerX + innerRadius * Math.cos(endRadians); const y2Inner = centerY + innerRadius * Math.sin(endRadians); return `M ${x1} ${y1} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${x2} ${y2} L ${x2Inner} ${y2Inner} A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${x1Inner} ${y1Inner} Z`; }; useEffect(() => { // 启动填充动画 progress.value = withTiming(1, { duration: 1500 }); }, []); let currentAngle = 0; return ( <View> <Svg width={centerX * 2} height={centerY * 2}> {data.map((value, index) => { const animatedAngle = (value / totalValue) * 360 * progress.value; const path = getArcPath(currentAngle, currentAngle + animatedAngle); currentAngle += (value / totalValue) * 360; return ( <AnimatedPath key={index} d={path} fill={colors[index]} /> ); })} </Svg> </View> ); }; export default CustomAnimatedDonut;
内容的提问来源于stack exchange,提问作者Yuva
相关产品推荐
相关产品推荐

