21

In my app I have a nested Touchable element. Every time I press on one of them, I got only one event. Can I propagate the inner downward the layer? Thanks in advance!

Code as follow:

    <TouchableHighlight style={{ flex: 1 }} onPress={() => { console.log('outer press') }}>
        <TouchableHighlight style={{ flex: 0.8, backgroundColor: 'blue' }} onPress={() => { console.log('inner press') }}>
            <Text>1</Text>
        </TouchableHighlight>
    </TouchableHighlight>
mannok
  • 1,712
  • 1
  • 20
  • 30

3 Answers3

20

A Touchables contains one local state, that is native to it and the other Touchables are not aware of it.

So when you touch a nested Touchable, the event gets propogated to the child element that access the state and does not release the resource unless it is complete

Here would be the life cycle in your case for the nested buttons, as mentioned in the docs

Parent: Parent Touchable
Child: Child Touchable

Parent onStartShouldSetResponder > Parent onResponderGrant > Parent onResponderTerminationRequest > Parent onResponderTerminate > Child onStartShouldSetResponder > Child onResponderGrant > Child onResponderRelease

Parent will not get access due to onResponderReject

If a parent View wants to prevent the child from becoming responder on a touch start, it should have a onStartShouldSetResponderCapture handler which returns true.

You may have a look into this video

Pritish Vaidya
  • 21,561
  • 3
  • 58
  • 76
  • 1
    Thx for your answer. For others want to have more details. You can search for `onStartShouldSetResponder` and `onStartShouldSetResponderCapture` – mannok Apr 16 '18 at 07:08
1

I've solved it by avoiding two nested Touchable* components. Using the onStartShouldSetResponderCapture or pointerEvents wasn't successful for what I tried to achieve.

Instead, I ended up using a view and its onTouchStart event, as it triggers in addition to the nested onPress event of a Touchable component. I still had to use pointerEvents="box-none" on the outer View.

<View
      pointerEvents="box-none"
      onTouchStart={(evt: GestureResponderEvent) => console.log("outerHandler")}>
       <TouchableOpacity
          onPress={(evt: GestureResponderEvent) => console.log("innerHandler")}>
              <Text>Press me</Text>
       </TouchableOpacity>
</View>
Michael Brenndoerfer
  • 3,483
  • 2
  • 39
  • 50
-4

Wouldn't you just remove the onPress for the outer? I am not sure I understand the question but try using event.preventDefault on the outer touchable highlight, to only access the inner one.

<TouchableHighlight style={{ flex: 1 }} onPress={(event) => { event.preventDefault() }}>
    <TouchableHighlight style={{ flex: 0.8, backgroundColor: 'blue' }} onPress={() => { console.log('inner press') }}>
        <Text>1</Text>
    </TouchableHighlight>
</TouchableHighlight>
Zain Budhwani
  • 61
  • 1
  • 3