ジェスチャーレスポンダーシステム
ジェスチャーレスポンダーシステムは、アプリ内のジェスチャーのライフサイクルを管理します。アプリがユーザーの意図を判断するにつれて、タッチはいくつかのフェーズを経ます。例えば、アプリはタッチがスクロールなのか、ウィジェット上のスライドなのか、それともタップなのかを判断する必要があります。これはタッチの最中でも変化する可能性があります。また、複数のタッチが同時に発生することもあります。
タッチレスポンダーシステムは、コンポーネントが親や子のコンポーネントに関する追加の知識なしに、これらのタッチインタラクションを交渉できるようにするために必要です。
ベストプラクティス
アプリの使い心地を良くするためには、すべてのアクションに以下の属性を持たせるべきです。
- フィードバック/ハイライト - ユーザーに何がタッチを処理しているのか、ジェスチャーを離したときに何が起こるのかを示します。
- キャンセル可能性 - アクションを起こしている最中に、ユーザーが指を離すことでタッチの途中で中断できるようにすべきです。
これらの機能は、ユーザーが間違いを恐れることなく実験したり対話したりできるため、アプリの使用感をより快適にします。
TouchableHighlight と Touchable*
レスポンダーシステムの使用は複雑になることがあります。そこで、「タップ可能」であるべきもののために、抽象的な`Touchable`実装を提供しています。これはレスポンダーシステムを使用し、タップのインタラクションを宣言的に設定することができます。ウェブでボタンやリンクを使用する場所ではどこでも`TouchableHighlight`を使用してください。
レスポンダーのライフサイクル
Viewは、適切なネゴシエーションメソッドを実装することでタッチレスポンダーになることができます。Viewがレスポンダーになりたいかどうかを尋ねるための2つのメソッドがあります。
View.props.onStartShouldSetResponder: evt => true,
- このViewはタッチの開始時にレスポンダーになりたいですか?View.props.onMoveShouldSetResponder: evt => true,
- レスポンダーではないView上でタッチが動くたびに呼ばれます:このViewはタッチの応答性を「要求」したいですか?
Viewがtrueを返し、レスポンダーになろうとすると、以下のいずれかが起こります。
View.props.onResponderGrant: evt => {}
- Viewがタッチイベントに応答するようになりました。これは、ハイライトしてユーザーに何が起こっているかを示すタイミングです。View.props.onResponderReject: evt => {}
- 何か別のものが現在レスポンダーであり、それを解放しません。
Viewが応答している場合、以下のハンドラが呼び出される可能性があります。
View.props.onResponderMove: evt => {}
- ユーザーが指を動かしています。View.props.onResponderRelease: evt => {}
- タッチの終了時、つまり "touchUp" で発火します。View.props.onResponderTerminationRequest: evt => true
- 何か別のものがレスポンダーになりたがっています。このViewはレスポンダーを解放すべきですか?trueを返すと解放が許可されます。View.props.onResponderTerminate: evt => {}
- レスポンダーがViewから奪われました。`onResponderTerminationRequest`の呼び出し後に他のViewによって奪われるか、OSによって(iOSのコントロールセンター/通知センターなどで)要求なしに奪われることがあります。
evt
は以下の形式を持つ合成タッチイベントです。
nativeEvent
changedTouches
- 前回のイベント以降に変更があったすべてのタッチイベントの配列identifier
- タッチのIDlocationX
- 要素に対するタッチのX座標locationY
- 要素に対するタッチのY座標pageX
- ルート要素に対するタッチのX座標pageY
- ルート要素に対するタッチのY座標target
- タッチイベントを受け取っている要素のノードIDtimestamp
- タッチの時間識別子。速度計算に便利です。touches
- 画面上の現在のすべてのタッチの配列
キャプチャShouldSetハンドラ
onStartShouldSetResponder
と`onMoveShouldSetResponder`はバブリングパターンで呼び出され、最も深いノードが最初に呼び出されます。これは、複数のViewが`*ShouldSetResponder`ハンドラに対してtrueを返した場合、最も深いコンポーネントがレスポンダーになることを意味します。これによりすべてのコントロールとボタンが使用可能になるため、ほとんどの場合これは望ましい動作です。
しかし、時には親がレスポンダーになることを確実にしたい場合があります。これはキャプチャフェーズを使用することで対応できます。レスポンダーシステムが最も深いコンポーネントからバブリングする前に、キャプチャフェーズが行われ、`on*ShouldSetResponderCapture`が発火します。したがって、親のViewがタッチ開始時に子がレスポンダーになるのを防ぎたい場合は、trueを返す`onStartShouldSetResponderCapture`ハンドラを持つべきです。
View.props.onStartShouldSetResponderCapture: evt => true,
View.props.onMoveShouldSetResponderCapture: evt => true,
PanResponder
より高レベルなジェスチャーの解釈については、PanResponderを確認してください。