Touch event is canceled on small move because element height is 0

On galaxy s6 touch is so sensitive that when you tap on the phone sometimes move event is fired. And because height in TouchableMixin._handleQueryLayout is 0 so because of that isTouchWithinActive will always be false and touch event will be canceled.

Now I am not sure how to fix because I am not sure how react-native is getting that value from the native component. Any help is appreciated

4 thoughts on “Touch event is canceled on small move because element height is 0

  1. Also getting the same conclusion here.

    The Bug

    Summary: All move related touch behavior functions incorrectly with react-native-svg.

    I created a demo project to demo this:
    https://github.com/chengyin/react-native-svg-press-bug

    Here is a GIF:

    You can see that in this sequence:

    1. Touch down
    2. Move within the Rect
    3. Touch up

    The expected behavior is onPress event is filed. Unfortunately for react-native-svg, this is not happening.

    Technical Details

    This line in RN’s Touchable determines whether the touch moved out of the view boundary or not. If the touch moved out of the boundary, onPressOut will be fired immediately. It also leads to that when the touch releases, onPress would not be fired.

    To perform this calculate, Touchable mixin saves the size and position of the element it is attached to to compare them to the touch event position. The measurement is done through UIManager on the native side using frame (for iOS). But this measurement is wrong for react-native-svg components because they are UIView subclass with zero frames. This wrong measurement makes Touchable treat almost all touch moves as if the they are out of the component touch area.

    This is particularly bad for 3D Touch enabled devices. When combining a Force Touch device (6s, 6s Plus, 7, 7 Plus) with an app that targets 9.0 and below.

    Due to an iOS SDK 9.0 bug, Force change triggers touchesMoved event call back (although the touch actually didn’t move), which leads to the touchableHandleResponderMove being called, and cancels out the press itself. Essentially, onPresss on react-native-svg components do not work at all on 6s, 6s Plus, 7, and 7 Plus. When the tap is very fast and light, it would work, but this is an unpractical expectation. This is reproducible in the Simulator with a 3D Touch enabled trackpad.

    Suggestions

    I would like to hear @magicismight‘s input on this, some options are:

    1. Fix frame on native SVG components. I am afraid that this bug here could lead to other unknown bugs.
    2. Override Touchable’s handlers to accommodate this limitation, either by cripple the touch support, or through offsetting the measurements from the native side to make them accurate.

    I’m more than happy to help here with the code.

  2. Not that I know of. One workaround, which cripple’s touch moved event, but makes onPress work is to disable the move responder:

    onPress: [[your press handler]]
    onResponderMove: function() { return; }
  3. Similar to the above comment, if you only care about the onPress event not touchMove events, you can explicitly use the onPressIn (or onPressOut). In testing it appeared to be slightly more responsive than having the onPanResponder just return.

Comments are closed.

Touch event is canceled on small move because element height is 0

On galaxy s6 touch is so sensitive that when you tap on the phone sometimes move event is fired. And because height in TouchableMixin._handleQueryLayout is 0 so because of that isTouchWithinActive will always be false and touch event will be canceled.

Now I am not sure how to fix because I am not sure how react-native is getting that value from the native component. Any help is appreciated

2 thoughts on “Touch event is canceled on small move because element height is 0

  1. Also getting the same conclusion here.

    The Bug

    Summary: All move related touch behavior functions incorrectly with react-native-svg.

    I created a demo project to demo this:
    https://github.com/chengyin/react-native-svg-press-bug

    Here is a GIF:

    You can see that in this sequence:

    1. Touch down
    2. Move within the Rect
    3. Touch up

    The expected behavior is onPress event is filed. Unfortunately for react-native-svg, this is not happening.

    Technical Details

    This line in RN’s Touchable determines whether the touch moved out of the view boundary or not. If the touch moved out of the boundary, onPressOut will be fired immediately. It also leads to that when the touch releases, onPress would not be fired.

    To perform this calculate, Touchable mixin saves the size and position of the element it is attached to to compare them to the touch event position. The measurement is done through UIManager on the native side using frame (for iOS). But this measurement is wrong for react-native-svg components because they are UIView subclass with zero frames. This wrong measurement makes Touchable treat almost all touch moves as if the they are out of the component touch area.

    This is particularly bad for 3D Touch enabled devices. When combining a Force Touch device (6s, 6s Plus, 7, 7 Plus) with an app that targets 9.0 and below.

    Due to an iOS SDK 9.0 bug, Force change triggers touchesMoved event call back (although the touch actually didn’t move), which leads to the touchableHandleResponderMove being called, and cancels out the press itself. Essentially, onPresss on react-native-svg components do not work at all on 6s, 6s Plus, 7, and 7 Plus. When the tap is very fast and light, it would work, but this is an unpractical expectation. This is reproducible in the Simulator with a 3D Touch enabled trackpad.

    Suggestions

    I would like to hear @magicismight‘s input on this, some options are:

    1. Fix frame on native SVG components. I am afraid that this bug here could lead to other unknown bugs.
    2. Override Touchable’s handlers to accommodate this limitation, either by cripple the touch support, or through offsetting the measurements from the native side to make them accurate.

    I’m more than happy to help here with the code.

  2. Not that I know of. One workaround, which cripple’s touch moved event, but makes onPress work is to disable the move responder:

    onPress: [[your press handler]]
    onResponderMove: function() { return; }

Comments are closed.