0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RuruCun個人開発Advent Calendar 2023

Day 23

ReactNative Expoでアプリ開発入門してみる Part4

Posted at

参考

ジェスチャーの実装に入っていきます。

ライブラリのインストール

ReactNativeGestureHandlerをインストールします。
また、ジェスチャー中のアニメーションを実装するために、react-native-reanimatedもインストールします。

$ npx expo install react-native-gesture-handler react-native-reanimated
$ npm install -D @babel/plugin-proposal-export-namespace-from 

ReanimatedのBabelプラグインをbabel.config.jsに追加します。

babel.config.js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      "@babel/plugin-proposal-export-namespace-from",
      "react-native-reanimated/plugin",
    ],
  };
};

開発サーバーを再起動します。
babel.config.jsの変更を反映させるために、-cをつけて起動しています。

$ npx expo start -c

アプリ内でジェスチャを動かすには、アプリの最上位にラップする必要があります。
App.jsに追加します。

App.js
import { GestureHandlerRootView } from "react-native-gesture-handler"; 

export default function App() {
  return (
    <GestureHandlerRootView style={styles.container}> 
    /* ...rest of the code remains */
    </GestureHandlerRootView>
  )
}

コンポーネントをアニメーション化する

EmojiStickerをアニメーション化します。
ImageComponentをAnimated.Imageに修正します。

EmojiSticker.js
import Animated from 'react-native-reanimated';

  <Animated.Image
    source={stickerSource}
    resizeMode="contain"
    style={{ width: imageSize, height: imageSize }}
  />

タップジェスチャを追加する

useSharedValueで、アニメーションに使う値を設定します。
今回は画像サイズをアニメーションに使います。

const scaleImage = useSharedValue(imageSize);

doubleTap時の処理を追加します。
下記のコードでは、2回タップされたら、画像のサイズを2倍にする処理になっています。

const doubleTap = Gesture.Tap()
  .numberOfTaps(2)
  .onStart(() => {
    if (scaleImage.value !== imageSize * 2) {
      scaleImage.value = scaleImage.value * 2;
    }
  });

useAnimatedStyle()で、アニメーションに使うStyleを設定します。

const imageStyle = useAnimatedStyle(() => {
  return {
    width: withSpring(scaleImage.value),
    height: withSpring(scaleImage.value),
  };
});

下記2点を行います。

  • GestureDetectorのgesturePropsへ、doubleTap時の処理を渡す。
  • Animated.ImageのStyleへ、useAnimatedStyle()で作成したimageStyleを追加する。
<GestureDetector gesture={doubleTap}>
    <Animated.Image
      source={stickerSource}
      resizeMode="contain"
      style={[imageStyle, { width: imageSize, height: imageSize }]}
    />
</GestureDetector>

すべてのコードは下記になります。

import { View } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, {
  useAnimatedStyle,
  useSharedValue,
  withSpring,
} from "react-native-reanimated";

export default function EmojiSticker({ imageSize, stickerSource }) {
  const scaleImage = useSharedValue(imageSize);
  const doubleTap = Gesture.Tap()
    .numberOfTaps(2)
    .onStart(() => {
      if (scaleImage.value !== imageSize * 2) {
        scaleImage.value = scaleImage.value * 2;
      }
    });
  const imageStyle = useAnimatedStyle(() => {
    return {
      width: withSpring(scaleImage.value),
      height: withSpring(scaleImage.value),
    };
  });

  return (
    <View style={{ top: -350 }}>
      <GestureDetector gesture={doubleTap}>
        <Animated.Image
          source={stickerSource}
          resizeMode="contain"
          style={{ width: imageSize, height: imageSize }}
        />
      </GestureDetector>
    </View>
  );
}

この変更後、アイコンをダブルタップ(Webではダブルクリック)することで、画像がアニメーションしながら2倍サイズになります。

パンジェスチャを追加する

EmojiSticker.jsのViewComponentをAnimatedにします。

+ <Animated.View style={{ top: -350 }}>
  <GestureDetector gesture={doubleTap}>
    {/* ...rest of the code remains same */}
  </GestureDetector>
+ </Animated.View>

X,Y座標を保存する値を、useSharedValueで作成します。

export default function EmojiSticker({ imageSize, stickerSource }) {
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);

  // ...rest of the code remains same
}

ダブルタップの処理を追加したときと似たように、Panジェスチャーを実装します。
onChangeイベントのeventから、指の位置を取得し、先程作成した、translate変数へ入れる処理にします。

const drag = Gesture.Pan()
.onChange((event) => {
  translateX.value += event.changeX;
  translateY.value += event.changeY;
});

useAnimatedStyleで座標のスタイルを作成します。

const containerStyle = useAnimatedStyle(() => {
  return {
    transform: [
      {
        translateX: translateX.value,
      },
      {
        translateY: translateY.value,
      },
    ],
  };
});

下記2点を行います。DoubleTapと同様です。

  • GestureDetectorを再度追加し、drag関数を渡す。
  • Animated.ViewのstyleへuseAnimatedStyleで作成したcontainerStyleを渡す。
+ <GestureDetector gesture={drag}>
+  <Animated.View style={[containerStyle, { top: -350 }]}>
    <GestureDetector gesture={doubleTap}>
      <Animated.Image
        source={stickerSource}
        resizeMode="contain"
        style={[imageStyle, { width: imageSize, height: imageSize }]}
      />
    </GestureDetector>
+  </Animated.View>
+ </GestureDetector>

上記でアイコンを好き場所にドラッグすることができるようになりました。

image.png
uploading...0

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?