様々なアプリやサービスで見かける、収縮する小さな円(ライト)をreact-native-skiaで表現してみます。
実装方法は簡単です。内側の円と外側の円を用意し、外側の円のサイズをアニメーションvalue値に従って動的に変更します。
const canvasSize = { width: props.radius * 4, height: props.radius * 4 }
const center = { x: canvasSize.width / 2, y: canvasSize.height / 2 }
const progress = useSharedValue(0)
useEffect(() => {
progress.value = withRepeat(
withTiming(1, {
easing: Easing.inOut(Easing.ease),
duration: 2200,
}),
-1,
true,
)
}, [])
const outerRadius = useDerivedValue(() => {
return interpolate(
progress.value,
[0, 1],
[props.radius * 1.5, props.radius * 1.9],
)
}, [props.radius])
return (
<Canvas style={canvasSize}>
{/* Outer Circle */}
<Circle
cx={center.x}
cy={center.y}
r={outerRadius}
color={props.color}
opacity={0.3}
>
<Blur blur={1} />
</Circle>
{/* Inner Circle */}
<Circle
cx={center.x}
cy={center.y}
r={props.radius}
color={props.color}
/>
{/* Inner Circle (ぼかし効果) */}
<Circle cx={center.x} cy={center.y} r={props.radius} color={props.color}>
<Blur blur={2} />
</Circle>
</Canvas>
)
内側の円に少しぼかし効果を出すため2つ円を重ねて一つにBlurを設定しています。
withRepeat
とwithTiming
でアニメーションを設定します。この設定をするとvalue値が0から1に繰り返し変化します。
progress.value = withRepeat(
withTiming(1, {
easing: Easing.inOut(Easing.ease),
duration: 2200,
}),
-1,
true,
)
外側の円の半径をアニメーションvalueを使って動的に変更します。
<Circle
cx={center.x}
cy={center.y}
r={outerRadius}
color={props.color}
opacity={0.3}
>
<Blur blur={1} />
</Circle>
可能であれば、今後より自然な表現になるよう改善していきたいと思います。
コードは以下で確認することが可能です。
https://github.com/gaishimo/omoidasu-tech-blog/tree/main/components/pages/2022-08-24-shrinking-circle