2022-08-24

react-native-skiaで収縮する円を表現する

様々なアプリやサービスで見かける、収縮する小さな円(ライト)をreact-native-skiaで表現してみます。

Loading 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を設定しています。

withRepeatwithTimingでアニメーションを設定します。この設定をすると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

最終更新: 2025-03-16 02:06
筆者: @gaishimo 主にReact Nativeでのアプリ開発を行っています。
© 2021 Omoidasu, Inc. All rights reserved.