React Native / 複数要素の同時タップをハンドリングしたい時

Shunsuke Sawada

ボタン2つ押したら何かする、みたいな時です。

Touchable

TouchableHighlight は同時に2つタップするということができないみたい。
片方タップしたらもう片方は反応しなかった。

jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MyComponent extends Component {

  constructor(props) {
    super(props);
    this.state = { text1: 'text 1', text2: 'text 2', text3: 'text 3' };
  }

  render() {
    return (
      <View>
        <TouchableHighlight onPress={() => { this.setState({ text1: 'touch started' }); }}>
          <Text>{this.state.text1}</Text>
        </TouchableHighlight>
        <TouchableHighlight onPress={() => { this.setState({ text2: 'touch started' }); }}>
          <Text>{this.state.text2}</Text>
        </TouchableHighlight>
      </View>
    );
  }
}

export default JobSearch;

View with Responder

Touchable ... のかわりに View を使って適切に Responder を設定する。
Touchable は複雑なレスポンダーの設定をやってくれているので便利だが、いろいろやりたい場合は自分で設定するしかない。
Gesture Responder System

TouchableHighlight and Touchable*
The responder system can be complicated to use. So we have provided an abstract Touchable implementation for things that should be "tappable". This uses the responder system and allows you to easily configure tap interactions declaratively. Use TouchableHighlight anywhere where you would use a button or link on web.

jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
render() {
  return (
    <View
      style={{ padding: 20 }}
      onStartShouldSetResponder={() => true}
      onResponderGrant={() => { this.setState({ text1: 'touch started' }); }}
      onResponderReject={() => { this.setState({ text1: 'touch started' }); }}
      onResponderRelease={() => { this.setState({ text1: 'text 1' }) }}
    >
      <Text>{this.state.text1}</Text>
    </View>

    <View
      style={{ padding: 20 }}
      onStartShouldSetResponder={() => true}
      onResponderGrant={() => { this.setState({ text2: 'touch started' }); }}
      onResponderReject={() => { this.setState({ text2: 'touch started' }); }}
      onResponderRelease={() => { this.setState({ text2: 'text 2' }); }}
    >
      <Text>{this.state.text2}</Text>
    </View>
  );
}

これで行けるだろうと思ったのですが、うまいこと行きません。。
onResponderReject は他の要素がアクティブで、タップが受け付つけられなかった時に発火するはずなのですが…

仕方がないので onTouchStart とかにしたらひとまず反応しました。
onTouchStart ってドキュメントには載ってないんだけどな…

jsx
1
2
3
4
5
6
7
8
9
10
11
12
render() {
  return (
    // ... 省略
    <View
      style={{ padding: 20 }}
      onTouchStart={() => { this.setState({ text3: 'touch started' }); }}
      onTouchEnd={() => { this.setState({ text3: 'text 3' }); }}
    >
      <Text>{this.state.text3}</Text>
    </View>
  );
}

↓ こんな感じです。

Shunsuke Sawada

おすすめの記事

webpackを使ってJSとCSSをコンパイルする(ES6 / Sass)
Turbolinks で Google adsense が正しく表示されない時の対処方法
5
RailsでGoogle mapsを使いこなすためのメモ 2 / 地図デザインのカスタマイズ
2