目次
1.やりたいこと
2.起きていた問題
3.原因
4.解決策
5.まとめ
1. やりたいこと
赤枠内の青の部分を「タップした時だけ」イベントを発火させたい
スクロールされた場合はタップと判定したくない
青部分をタップしたときにキーボードを非表示にするという処理をしたい。
2. 起きていた問題
FlatListのonPressやonTouchEndやonTouchStartを使用して、
普通にタップのイベントを拾い処理を行おうとしたが、
単純に上記イベントを契機とするとスクロールした際にもイベントが発火してしまう問題が発生していました。
3. 原因
おそらくFlatList自体をタップした際のことは考えらておらず、
onpressとスクロールを判別するすべはReactNative API上にはない。
そのため自前でonPressとScrollの判定を行う.
4. 解決策
そのため、スクロールとタップの挙動の違いである
下記をもとにタップ判定をすることを考えた。
①タップ開始位置と終了位置 スクロール→違う タップ→ほぼ同じ
②タップ時間の長さ スクロール→長い タップ→短い
今回は①の違いを利用してX, Yの座標が同じであれば、
タップと判定する。それ以外はタップではないと判定する。
onTouchStart = ({nativeEvent}) => {
const { locationX, locationY } = nativeEvent
this.setState({ locationX, locationY })
}
onTouchEnd = ({nativeEvent}) => {
const { locationX, locationY } = nativeEvent
if(this.state.locationX == locationX && this.state.locationY == locationY){
this.hideKeyboard(this.props)
}
}
<FlatList data={data}
onTouchStart={this.onTouchStart}
onTouchEnd={this.onTouchEnd}
renderItem={this.renderItem}/>
最初は上記のコードだったが、
スマホによっては、性能がよくない場合があり、
図らずもタップがずれてしまうこともあるので、
余白を追加する。
今回は半径8pxの範囲未満であれば、タップと認識するようにした。
/**
* タップ開始時と終了時の座標が半径8px以内に収まっていればタップとして認識する
* タップの場合、キーボードをOFFにする
*/
const ACCEPTBALE_LOCATION_GAP = 8
onTouchStart = ({nativeEvent}) => {
const { locationX, locationY } = nativeEvent
this.setState({ locationX, locationY })
}
onTouchEnd = ({nativeEvent}) => {
const { locationX, locationY } = nativeEvent
if(this.state.locationX - ACCEPTBALE_LOCATION_GAP < locationX && locationX < this.state.locationX + ACCEPTBALE_LOCATION_GAP
&& this.state.locationY - ACCEPTBALE_LOCATION_GAP < locationY && locationY < this.state.locationY + ACCEPTBALE_LOCATION_GAP){
this.hideKeyboard()// ex. Keyboard OFFの処理
}
}
<FlatList data={data}
onTouchStart={this.onTouchStart}
onTouchEnd={this.onTouchEnd}
renderItem={renderItem}/>
5. まとめ
ものすごく単純な処理で終わると思いきや、
ひと工夫する必要があった。
あまり調べた際に参考資料が出てこなかったので、
この記事を作成しました。
もっといいやり方があるよ!などあればぜひコメントまで!
では!