如何在支持3d touch(强制触摸)的设备上进行TouchableOpacity或TouchableHighlight可点击

时间:2017-02-01 15:09:58

标签: ios react-native react-native-ios touchableopacity touchablehighlight

我有这段代码:

<View {...this.panGesture.panHandlers}>
    <Animated.View>

        <View style={{ position: 'absolute' }}>
            <TouchableHighlight onPress={ () => {console.log('hello')}>
            </TouchableHighlight>
        </View>

    </Animated.View>
</View>

我无法为我的爱而让onPress适用于iPhone 6s及更高版本,当启用3d触控时。

我已经尝试了大多数建议here的解决方案,但没有运气。

我很感激任何帮助!

2 个答案:

答案 0 :(得分:2)

我已经能够通过确保父PanResponder在移动时没有抓住响应者来解决这个特定问题,直到触摸实际上从原点移开:

PanResponder.create({

  //... other responder callbacks

  onMoveShouldSetPanResponder(e, gestureState) {
    if (gestureState.dx === 0 || gestureState.dy === 0) {
      return false;
    }
    return true;
  }
});

这是在React Native 0.10天左右回来的,之后没有尝试过。希望它有所帮助!

答案 1 :(得分:0)

好了解了很多这个,我意识到解决方案部分是jevakallio说的但是当我启用3D触摸时我不能再使用Touchables所以我必须手动重现他们的行为。

我的代码现在看起来像这样: 代码:

let touchable;

if (View.forceTouchAvailable === false) { // if 3d touch is disabled
    // just use a Touchable and all should be fine.
    touchable = (<TouchableHighlight
        onPress={ () => {console.log('hello world');}
        style={this.props.style}
        underlayColor={this.props.highlightBgColor}
    >
        {this.props.children}
    </TouchableHighlight>);
} else { // Otherwise if 3D touch is enabled
    // we'll have to use a child view WITH a PanResponder
    touchable = (<View
      style={[this.props.style, {
        backgroundColor: this.state.panViewIsTapped ?
          this.props.highlightBgColor
          :
          bgColor,
      }]}
      {...this.panResponderChild.panHandlers}
    >
      {this.props.children}
    </View>);
}

return (<View {...this.panResponderParent.panHandlers}>
    <Animated.View>

        <View style={{ position: 'absolute' }}>
            {touchable}
        </View>

    </Animated.View>
</View>);

孩子泛响应者代码(this.panResponderChild):

this.panResponderChild = PanResponder.create({

        // true because we want tapping on this to set it as the responder
        onStartShouldSetPanResponder: () => true,

        // true because we want this to capture the responder lock from it's parent on start
        onStartShouldSetPanResponderCapture: () => true,

        // when the pan responder lock is terminated, set the pan view as NOT tapped
        onPanResponderTerminate: () => {
          this.setState({ panViewIsTapped: false });
        },

        // true so that the parent can grab our responder lock if he wan'ts to.
        onPanResponderTerminationRequest: () => true,

        // false because we DON'T want this btn capturing the resp lock from it's parent on move
        onMoveShouldSetPanResponderCapture: () => false,

        // false because we DON'T want moving the finger on this to set it as the responder
        onMoveShouldSetPanResponder: () => false,

        onPanResponderGrant: () => {
          this.setState({ panViewIsTapped: true });
        },

        onPanResponderRelease: () => {
          this.setState({ panViewIsTapped: false });
          console.log('hello world');
        },
})

泛响应者代码(this.panResponderParent):

this.panResponderParent = PanResponder.create({

      // true because we want tapping on the cal, to set it as a responder
      onStartShouldSetPanResponder: () => true,

      // false because we DON'T want to grab the responder lock from our children on start
      onStartShouldSetPanResponderCapture: () => false,

      /*
      onMoveShouldSetPanResponderCapture:
        false because we don't want to accidentally grab the responder lock from
        our children on movement.
          That's because sometimes even a small tap contains movement,
          and thus a big percentage of taps will not work.
          Keeping that flag false does not nessecarily mean that our children will
         always capture the responder lock on movement, (they can if they want),
         we're just not strict enough to grab it from them.
      */
      onMoveShouldSetPanResponderCapture: () => false,

      /*
      onMoveShouldSetPanResponder:
        We DO want moving the finter on the cal, to set it as a responder,
        BUT, we don't always want moving the finger on an appointment setting this parent
        as the responder.

        Logic:
        So, when the dx AND dy of the pan are 0, we return false, because we don't
        want to grab the responder from our appointment children.

        For anything other than that we just allow this parent to become the responder.

        (dx, dy: accumulated distance of the gesture since the touch started)
      */
      onMoveShouldSetPanResponder: (e, gestureState) =>
        !(gestureState.dx === 0 || gestureState.dy === 0),


    });