React Native Reanimated 2(基于路由的动画 SVG 已更改)
React Native Reanimated 2 (Animate SVG based on route changed)
我有一个 React 功能组件 Svg
用作 Bottom-TabBar 的图标。在路线更改时,将当前 state.index
与路线 index
进行比较。本质上是布尔状态 isFocused
的结果被传递给 Svg.
我正在尝试根据此状态为 Svg 设置动画,但无法使用重新设置动画完成简单操作。我最确定 fill 的值没有在 useAnimatedProps
钩子中更新,但我缺乏对 reanimated 有深入了解的经验。任何帮助将不胜感激
import Animated, {
useAnimatedProps,
useSharedValue,
} from 'react-native-reanimated';
import Svg, { Circle, Path } from 'react-native-svg';
const AnimatedSvg = Animated.createAnimatedComponent(Svg);
export default ({ isFocused }) => {
const fill = useSharedValue({ fill: 'transparent' });
const animatedProps = useAnimatedProps(() => {
isFocused
? (fill.value = { fill: 'red' })
: (fill.value = { fill: 'transparent' });
return fill.value;
});
return (
<AnimatedSvg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
animatedProps={animatedProps}
stroke={'white'}
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
className="feather feather-search">
<Circle cx={11} cy={11} r={8} />
<Path d="m21 21-4.35-4.35" />
</AnimatedSvg>
);
};
一种更常见的方法是使用“进度变量”作为共享值。
const fillProgress = useSharedValue(isFocused? 1 : 0);
您将使用此进度变量来生成动画道具。请注意使用 interpolateColor
来获取实际的插值颜色。
const animatedProps = useAnimatedProps(() => {
const fillValue = interpolateColor(fillProgress.value, [0, 1], ["transparent", "red"]);
return {
fill: fillValue
}
});
您必须 return 一个具有您想要动画的属性的对象。例如,如果您想为填充和不透明度设置动画,您可以使用适当的值 return {fill: "", opacity: -1}
而不是 ""
和 -1
。最后,你必须制作你想要动画的实际元素。在这种情况下,您想要为 Circle
设置动画,而不是 Svg
,因此它必须是一个动画对象。
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
然后您可以使用 useEffect
检测正在聚焦并相应地设置动画。
useEffect(() => {
fillProgress.value = withTiming(isFocused? 1 : 0);
}, [isFocused]);
记得像在 withTiming
函数中一样设置 fillProgress
的初始值。
总而言之,您必须为使用动画属性的元素设置动画,并且您应该如上所述使用进度变量。
这是完整的修改代码(在 Android 上测试):
import Animated, {
useAnimatedProps,
useSharedValue,
} from 'react-native-reanimated';
import Svg, { Circle, Path } from 'react-native-svg';
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
export default function Icon ({ isFocused }) {
const fillProgress = useSharedValue(isFocused? 1 : 0);
const animatedProps = useAnimatedProps(() => {
const fillValue = interpolateColor(fillProgress.value, [0, 1], ["transparent", "red"]);
return {
fill: fillValue
}
});
useEffect(() => {
fillProgress.value = withTiming(isFocused? 1 : 0);
}, [isFocused]);
return (
<Svg
width={24}
height={24}
stroke={'white'}
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
className="feather feather-search">
<AnimatedCircle animatedProps={animatedProps} cx={11} cy={11} r={8} />
<Path d="m21 21-4.35-4.35" />
</Svg>
);
};
我有一个 React 功能组件 Svg
用作 Bottom-TabBar 的图标。在路线更改时,将当前 state.index
与路线 index
进行比较。本质上是布尔状态 isFocused
的结果被传递给 Svg.
我正在尝试根据此状态为 Svg 设置动画,但无法使用重新设置动画完成简单操作。我最确定 fill 的值没有在 useAnimatedProps
钩子中更新,但我缺乏对 reanimated 有深入了解的经验。任何帮助将不胜感激
import Animated, {
useAnimatedProps,
useSharedValue,
} from 'react-native-reanimated';
import Svg, { Circle, Path } from 'react-native-svg';
const AnimatedSvg = Animated.createAnimatedComponent(Svg);
export default ({ isFocused }) => {
const fill = useSharedValue({ fill: 'transparent' });
const animatedProps = useAnimatedProps(() => {
isFocused
? (fill.value = { fill: 'red' })
: (fill.value = { fill: 'transparent' });
return fill.value;
});
return (
<AnimatedSvg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
animatedProps={animatedProps}
stroke={'white'}
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
className="feather feather-search">
<Circle cx={11} cy={11} r={8} />
<Path d="m21 21-4.35-4.35" />
</AnimatedSvg>
);
};
一种更常见的方法是使用“进度变量”作为共享值。
const fillProgress = useSharedValue(isFocused? 1 : 0);
您将使用此进度变量来生成动画道具。请注意使用 interpolateColor
来获取实际的插值颜色。
const animatedProps = useAnimatedProps(() => {
const fillValue = interpolateColor(fillProgress.value, [0, 1], ["transparent", "red"]);
return {
fill: fillValue
}
});
您必须 return 一个具有您想要动画的属性的对象。例如,如果您想为填充和不透明度设置动画,您可以使用适当的值 return {fill: "", opacity: -1}
而不是 ""
和 -1
。最后,你必须制作你想要动画的实际元素。在这种情况下,您想要为 Circle
设置动画,而不是 Svg
,因此它必须是一个动画对象。
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
然后您可以使用 useEffect
检测正在聚焦并相应地设置动画。
useEffect(() => {
fillProgress.value = withTiming(isFocused? 1 : 0);
}, [isFocused]);
记得像在 withTiming
函数中一样设置 fillProgress
的初始值。
总而言之,您必须为使用动画属性的元素设置动画,并且您应该如上所述使用进度变量。
这是完整的修改代码(在 Android 上测试):
import Animated, {
useAnimatedProps,
useSharedValue,
} from 'react-native-reanimated';
import Svg, { Circle, Path } from 'react-native-svg';
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
export default function Icon ({ isFocused }) {
const fillProgress = useSharedValue(isFocused? 1 : 0);
const animatedProps = useAnimatedProps(() => {
const fillValue = interpolateColor(fillProgress.value, [0, 1], ["transparent", "red"]);
return {
fill: fillValue
}
});
useEffect(() => {
fillProgress.value = withTiming(isFocused? 1 : 0);
}, [isFocused]);
return (
<Svg
width={24}
height={24}
stroke={'white'}
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
className="feather feather-search">
<AnimatedCircle animatedProps={animatedProps} cx={11} cy={11} r={8} />
<Path d="m21 21-4.35-4.35" />
</Svg>
);
};