[ReactNative] subviewからタッチイベントを奪う


ネイティブアプリにおいて, ちょっと面倒だけどよく使うものの1つにsubviewのタッチイベントを無効化して, superviewがタッチイベントを処理したいケースというのがある.
iOSでいうところのUIView # hitTest:withEvent:で行う処理である.

ReactNativeの場合にどうするか, 割と分かりにくいところに書いてあったので備忘録的に書いておこうと思う.

ReactNativeでは最も深い位置のsubviewから順にresponderの判定が行われる

そもそもReactNativeでTouchableを扱おうとする場合, TouchableWithoutFeedbackを用いた派生クラスを用いる. 派生クラスと書いているが, 基本的には継承関係になく, これらを子に持つComponentである.

これらがResponderになる為のフローはGesture Responder Systemにおいて記載がある.
onStartShouldSetResponderの返り値によって, subviewから順番にresponderになるターゲットを判断するようだ.
コードでいうと, ここらへんにある.

ところで, responderの判定の仕方がiOSとは全く異なるというのが面白い. iOSはrootから順番にUIView # hitTest:withEvent:を呼び出していき, superviewからsubviewへと判断される.
一方で, ReactNativeはsubviewからsuperviewへと判定されていくのがデフォルトの挙動である.

onStartShouldSetResponder and onMoveShouldSetResponder are called with a bubbling pattern, where the deepest node is called first.

Gesture Responder Systemより

SuperviewがResponderになる方法

disabledを使う方法

先にhack的な方法を紹介する. ドキュメントに辿り着くまでにググって出てきた方法はこちらだった.

disabledを設定することでここでonStartShouldSetResponderがfalseになることを使う方法である.
しかし, この方法だとdisabled用のstyleが適用されてしまう. そこで, styleを自分で指定することでそれっぽい見た目にする.

onStartShouldSetResponderCaptureを使う方法

Gesture Responder Systemに記載されている, Superviewがresponderになる方法を使う.
これで設定したComponentの子要素がresponderにならずに, 設定したComponent自身がresponderになることができる.
但し, 一般的なTouchableWithoutFeedbackなどではこの値が子要素に伝搬されていない為, 使うことができなかったりする.


投稿を作成しました 11

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連する投稿

検索語を上に入力し、 Enter キーを押して検索します。キャンセルするには ESC を押してください。