gpt4 book ai didi

javascript - 动画化 的 react-native-svg 短划线长度

转载 作者:数据小太阳 更新时间:2023-10-29 04:30:44 25 4
gpt4 key购买 nike

大家好,我正在尝试实现类似于:https://kimmobrunfeldt.github.io/progressbar.js 的效果(圈出一个)

在使用 setNativeProps 方法之前,我能够成功地为一些 svg 元素制作动画,但是这次我用破折号长度失败了,下面是一个演示当前行为的 gif(圆圈从完整变为收到新 Prop 时半满):

enter image description here

从本质上讲,我正在尝试为这个变化设置动画,而不是它只是轻弹进来,下面是这个矩形进度条的完整源代码,基本思想是使用 CirclestrokeDasharray 为了显示循环进度,它接收 currentExpnextExp 作为 Angular 色经验的值,以计算他们到达下一个 lvl 之前剩余的百分比。

组件使用非常标准的元素集,除了来自样式表和 styled-components 库的少量尺寸/动画和颜色 Prop 用于样式。

注意:项目正在从 expo.io 导入这个库但它本质上是 react-native-svg

import React, { Component } from "react";
import PropTypes from "prop-types";
import styled from "styled-components/native";
import { Animated } from "react-native";
import { Svg } from "expo";
import { colour, dimension, animation } from "../Styles";

const { Circle, Defs, LinearGradient, Stop } = Svg;

const SSvg = styled(Svg)`
transform: rotate(90deg);
margin-left: ${dimension.ExperienceCircleMarginLeft};
margin-top: ${dimension.ExperienceCircleMarginTop};
`;

class ExperienceCircle extends Component {
// -- prop validation ----------------------------------------------------- //
static propTypes = {
nextExp: PropTypes.number.isRequired,
currentExp: PropTypes.number.isRequired
};

// -- state --------------------------------------------------------------- //
state = {
percentage: new Animated.Value(0)
};

// -- methods ------------------------------------------------------------- //
componentDidMount() {
this.state.percentage.addListener(percentage => {
const circumference = dimension.ExperienceCircleRadius * 2 * Math.PI;
const dashLength = percentage.value * circumference;
this.circle.setNativeProps({
strokeDasharray: [dashLength, circumference]
});
});
this._onAnimateExp(this.props.nextExp, this.props.currentExp);
}

componentWillReceiveProps({ nextExp, currentExp }) {
this._onAnimateExp(currentExp, nextExp);
}

_onAnimateExp = (currentExp, nextExp) => {
const percentage = currentExp / nextExp;
Animated.timing(this.state.percentage, {
toValue: percentage,
duration: animation.duration.long,
easing: animation.easeOut
}).start();
};

// -- render -------------------------------------------------------------- //
render() {
const { ...props } = this.props;
// const circumference = dimension.ExperienceCircleRadius * 2 * Math.PI;
// const dashLength = this.state.percentage * circumference;
return (
<SSvg
width={dimension.ExperienceCircleWidthHeight}
height={dimension.ExperienceCircleWidthHeight}
{...props}
>
<Defs>
<LinearGradient
id="ExperienceCircle-gradient"
x1="0"
y1="0"
x2="0"
y2={dimension.ExperienceCircleWidthHeight * 2}
>
<Stop
offset="0"
stopColor={`rgb(${colour.lightGreen})`}
stopOpacity="1"
/>
<Stop
offset="0.5"
stopColor={`rgb(${colour.green})`}
stopOpacity="1"
/>
</LinearGradient>
</Defs>
<Circle
ref={x => (this.circle = x)}
cx={dimension.ExperienceCircleWidthHeight / 2}
cy={dimension.ExperienceCircleWidthHeight / 2}
r={dimension.ExperienceCircleRadius}
stroke="url(#ExperienceCircle-gradient)"
strokeWidth={dimension.ExperienceCircleThickness}
fill="transparent"
strokeDasharray={[0, 0]}
strokeLinecap="round"
/>
</SSvg>
);
}
}

export default ExperienceCircle;

更新:通过发布到react-native-svg repo: https://github.com/react-native-community/react-native-svg/issues/451 的问题可获得扩展讨论和更多示例(适用于不同元素的类似方法)

最佳答案

当您知道 SVG 输入如何工作时,这实际上非常简单,react-native-SVG(或 SVG 输入,一般来说,它不适用于 Angular )的问题之一,所以当您想要在一个圆上工作,你需要将 Angular 转换为它所需要的输入,这可以通过简单地编写一个函数来完成(你不一定需要记住或完全理解转换是如何工作的,这是标准的):

result

function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}

然后你添加另一个函数,它可以以正确的格式为你提供 d 属性:

function describeArc(x, y, radius, startAngle, endAngle){

var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);

var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";

var d = [
"M", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");

return d;
}

现在太好了,您有了函数 (describeArc),它为您提供了描述路径(圆弧)所需的完美参数:所以你可以将 PATH 定义为:

<AnimatedPath d={_d} stroke="red" strokeWidth={5} fill="none"/>

例如,如果您需要半径 R 在 45 度到 90 度之间的圆弧,只需将 _d 定义为:

_d = describeArc(R, R, R, 45, 90);

现在我们已经了解了 SVG PATH 的工作原理,我们可以实现 React Native 动画,并定义一个动画状态,例如 progress:

import React, {Component} from 'react';
import {View, Animated, Easing} from 'react-native';
import Svg, {Circle, Path} from 'react-native-svg';

AnimatedPath = Animated.createAnimatedComponent(Path);

class App extends Component {
constructor() {
super();
this.state = {
progress: new Animated.Value(0),
}
}
componentDidMount(){
Animated.timing(this.state.progress,{
toValue:1,
duration:1000,

}).start()
}



render() {
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}

function describeArc(x, y, radius, startAngle, endAngle){

var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);

var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";

var d = [
"M", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");

return d;
}

let R = 160;
let dRange = [];
let iRange = [];
let steps = 359;
for (var i = 0; i<steps; i++){
dRange.push(describeArc(160, 160, 160, 0, i));
iRange.push(i/(steps-1));
}


var _d = this.state.progress.interpolate({
inputRange: iRange,
outputRange: dRange
})

return (
<Svg style={{flex: 1}}>
<Circle
cx={R}
cy={R}
r={R}
stroke="green"
strokeWidth="2.5"
fill="green"
/>
{/* X0 Y0 X1 Y1*/}
<AnimatedPath d={_d}
stroke="red" strokeWidth={5} fill="none"/>

</Svg>
);
}
}

export default App;

这个简单的组件将如您所愿地工作

  • 在组件的顶部,我们写,

AnimatedPath = Animated.createAnimatedComponent(Path);

因为从 react-native-svg 导入的 Path 不是原生的 react-native 组件,我们通过它把它变成动画。

  • constructor 中,我们将进度定义为动画期间应更改的动画状态。

  • componentDidMount 开始动画过程。

  • render 方法的开头,声明了定义SVG d 参数所需的两个函数(polarToCartesiandescribeArc).

  • 然后在 this.state.progress 上使用 react-native interpolate 来插入 this.state.progress 中的变化从 0 到 1,进入 d 参数的变化。但是,这里有两点您应该牢记:

    1- 两条不同长度的圆弧之间的变化不是线性的,所以从 Angular 0 到 360 的线性插值不能如你所愿,因此最好将动画定义为 n 度的不同步长(我使用了 1 度,您可以根据需要增加或减少它。)。

    2-圆弧不能延续到360度(因为相当于0度),所以最好在接近但不等于360度(比如359.9)结束动画

  • 在返回部分的末尾,描述了 UI。

关于javascript - 动画化 <Circle/> 的 react-native-svg 短划线长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46142291/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com