使用 react-native animated api 与原点的 react-native-svg 旋转等同于什么
What's the equivalent of react-native-svg rotation with origins using react-native animated api
我有下面的 svg 路径,它在每个 value
状态成功更改时围绕原点旋转,其中值是某个度值:
<Path
transform={{
rotation: this.state.value,
originX: width / 2,
originY: height / 2
}}
d={`M ${width * 0.5} ${height * 0.5} L${width * 0.75} ${height * 0.75}`} //the actual path does not matter
fill={Colors.black}
stroke={Colors.black}
/>
我每 ~20 毫秒在 value
上调用 setState,但这不够平滑,+ 这不是推荐的转换方式。
我想要实现的是使用动画 API 对旋转进行动画处理,以实现更平滑的旋转。
我已经尝试让我的 value
状态成为 Animated.Value
。然后将 Path
设为 Animated.createAnimatedComponent(Path)
并调用:
Animated.timing(this.state.value, {
toValue: newDegreesValue,
duration: 1000,
useNativeDriver: true
}).start();
然后我这样渲染路径:
<Path
style={transform:[{
rotate: this.state.value
}]}
d={`M ${width * 0.5} ${height * 0.5} L${width * 0.75} ${height * 0.75}`} //the actual path does not matter
fill={Colors.black}
stroke={Colors.black}
/>
与之前使用状态的工作代码相比,这根本不起作用。原因之一是动画 API 不支持的 originX、originY 值,我不知道如何替换,但我不确定这是唯一的原因,也许 rotate
有点不同比 rotation
属性 还多?。
所以,问题是,如何使用动画 api?
来实现不断调用 setState 的代码的相同结果
你需要使用插值
const animation=this.state.value.interpolate({
inputRange: [0, 360],
outputRange: ['0deg', '360deg'],
});
<Path
style={transform:[{
rotate:animation
}]}
这是我实现它的方式:
// init the animatedComponents
const NeedlePath = Animated.createAnimatedComponent(Path);
const AnimatedG = Animated.createAnimatedComponent(G);
// set the animation
Animated.timing(this.state.angle, {
toValue: 240, // degrees
duration: 1000,
useNativeDriver: true
}).start();
// pivotX and pivotY are the originX, originY points.
// the width and height are calculated dynamically, so that the whole svg is a square (equal height width), and the center of it are my origins.
render() {
let height = this.state.height;
let width = this.state.width;
let [pivotX, pivotY] = [0, 0];
if (height && width) {
[pivotX, pivotY] = [width / 2, height / 2];
}
return (
<View
style={{ flex: 1}}
onLayout={event => {
this.findDimesions(event.nativeEvent.layout); // find height and width dynamically, so that this remain a square container with same height and width
}}
>
{height !== undefined && width !== undefined && (
<Svg height={height} width={width} style={{ alignItems: "center" }}>
<G transform={`translate(${pivotX}, ${pivotY})`}>
<AnimatedG
style={{
transform: [
{
rotate: this.state.angle.interpolate({
inputRange: [0, 360],
outputRange: [`0deg`, `360deg`]
})
}
]
}}
>
<NeedlePath
transform={`translate(-${pivotX} -${pivotY})`}
d={`M ${width * 0.5} ${height * 0.5} L${width * 0.5 + width * 0.25} ${height * 0.5 + height * 0.25}`}
fill={Colors.black}
stroke={Colors.black}
/>
</AnimatedG>
</G>
</Svg>
)}
</View>
);
}
style={{ alignItems: "center" }}
对于在 android 上获得相同的结果也很重要,而不是使用 offsetAndroid 设置 translationX 和 translationY。这适用于版本 v9.13.3
的 react-native-svg。也许在较新的版本中这会受到影响,因为修复了翻译问题,我不知道这里的代码会受到什么影响。您可以参考 here 以获取有关 android
上需要偏移量的翻译的更多信息
我有下面的 svg 路径,它在每个 value
状态成功更改时围绕原点旋转,其中值是某个度值:
<Path
transform={{
rotation: this.state.value,
originX: width / 2,
originY: height / 2
}}
d={`M ${width * 0.5} ${height * 0.5} L${width * 0.75} ${height * 0.75}`} //the actual path does not matter
fill={Colors.black}
stroke={Colors.black}
/>
我每 ~20 毫秒在 value
上调用 setState,但这不够平滑,+ 这不是推荐的转换方式。
我想要实现的是使用动画 API 对旋转进行动画处理,以实现更平滑的旋转。
我已经尝试让我的 value
状态成为 Animated.Value
。然后将 Path
设为 Animated.createAnimatedComponent(Path)
并调用:
Animated.timing(this.state.value, {
toValue: newDegreesValue,
duration: 1000,
useNativeDriver: true
}).start();
然后我这样渲染路径:
<Path
style={transform:[{
rotate: this.state.value
}]}
d={`M ${width * 0.5} ${height * 0.5} L${width * 0.75} ${height * 0.75}`} //the actual path does not matter
fill={Colors.black}
stroke={Colors.black}
/>
与之前使用状态的工作代码相比,这根本不起作用。原因之一是动画 API 不支持的 originX、originY 值,我不知道如何替换,但我不确定这是唯一的原因,也许 rotate
有点不同比 rotation
属性 还多?。
所以,问题是,如何使用动画 api?
你需要使用插值
const animation=this.state.value.interpolate({
inputRange: [0, 360],
outputRange: ['0deg', '360deg'],
});
<Path
style={transform:[{
rotate:animation
}]}
这是我实现它的方式:
// init the animatedComponents
const NeedlePath = Animated.createAnimatedComponent(Path);
const AnimatedG = Animated.createAnimatedComponent(G);
// set the animation
Animated.timing(this.state.angle, {
toValue: 240, // degrees
duration: 1000,
useNativeDriver: true
}).start();
// pivotX and pivotY are the originX, originY points.
// the width and height are calculated dynamically, so that the whole svg is a square (equal height width), and the center of it are my origins.
render() {
let height = this.state.height;
let width = this.state.width;
let [pivotX, pivotY] = [0, 0];
if (height && width) {
[pivotX, pivotY] = [width / 2, height / 2];
}
return (
<View
style={{ flex: 1}}
onLayout={event => {
this.findDimesions(event.nativeEvent.layout); // find height and width dynamically, so that this remain a square container with same height and width
}}
>
{height !== undefined && width !== undefined && (
<Svg height={height} width={width} style={{ alignItems: "center" }}>
<G transform={`translate(${pivotX}, ${pivotY})`}>
<AnimatedG
style={{
transform: [
{
rotate: this.state.angle.interpolate({
inputRange: [0, 360],
outputRange: [`0deg`, `360deg`]
})
}
]
}}
>
<NeedlePath
transform={`translate(-${pivotX} -${pivotY})`}
d={`M ${width * 0.5} ${height * 0.5} L${width * 0.5 + width * 0.25} ${height * 0.5 + height * 0.25}`}
fill={Colors.black}
stroke={Colors.black}
/>
</AnimatedG>
</G>
</Svg>
)}
</View>
);
}
style={{ alignItems: "center" }}
对于在 android 上获得相同的结果也很重要,而不是使用 offsetAndroid 设置 translationX 和 translationY。这适用于版本 v9.13.3
的 react-native-svg。也许在较新的版本中这会受到影响,因为修复了翻译问题,我不知道这里的代码会受到什么影响。您可以参考 here 以获取有关 android