react-native-navigation的迁移库

TouchablePreview.tsx 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import * as React from 'react';
  2. import * as PropTypes from 'prop-types';
  3. import {
  4. View,
  5. Platform,
  6. findNodeHandle,
  7. TouchableOpacity,
  8. TouchableHighlight,
  9. TouchableNativeFeedback,
  10. TouchableWithoutFeedback,
  11. GestureResponderEvent,
  12. NativeTouchEvent,
  13. NativeSyntheticEvent,
  14. } from 'react-native';
  15. // Polyfill GestureResponderEvent type with additional `force` property (iOS)
  16. interface NativeTouchEventWithForce extends NativeTouchEvent { force: number; }
  17. interface GestureResponderEventWithForce extends NativeSyntheticEvent<NativeTouchEventWithForce> {}
  18. export interface Props {
  19. children: React.ReactNode;
  20. touchableComponent?: TouchableHighlight | TouchableOpacity | TouchableNativeFeedback | TouchableWithoutFeedback | React.ReactNode;
  21. onPress?: () => void;
  22. onPressIn?: (reactTag?) => void;
  23. onPeekIn?: () => void;
  24. onPeekOut?: () => void;
  25. }
  26. const PREVIEW_DELAY = 350;
  27. const PREVIEW_MIN_FORCE = 0.1;
  28. const PREVIEW_TIMEOUT = 1250;
  29. export class TouchablePreview extends React.PureComponent<Props, any> {
  30. static propTypes = {
  31. children: PropTypes.node,
  32. touchableComponent: PropTypes.func,
  33. onPress: PropTypes.func,
  34. onPressIn: PropTypes.func,
  35. onPeekIn: PropTypes.func,
  36. onPeekOut: PropTypes.func,
  37. };
  38. static defaultProps = {
  39. touchableComponent: TouchableWithoutFeedback,
  40. };
  41. static peeking = false;
  42. private timeout: number | undefined;
  43. private ts: number = 0;
  44. private onRef = React.createRef<any>();
  45. onPress = () => {
  46. const { onPress } = this.props;
  47. if (typeof onPress !== 'function' || TouchablePreview.peeking) {
  48. return;
  49. }
  50. return onPress();
  51. }
  52. onPressIn = () => {
  53. if (Platform.OS === 'ios') {
  54. const { onPressIn } = this.props;
  55. if (!onPressIn) {
  56. return;
  57. }
  58. const reactTag = findNodeHandle(this.onRef.current);
  59. return onPressIn({ reactTag });
  60. }
  61. // Other platforms don't support 3D Touch Preview API
  62. return null;
  63. }
  64. onTouchStart = (event: GestureResponderEvent) => {
  65. // Store a timstamp of the initial touch start
  66. this.ts = event.nativeEvent.timestamp;
  67. }
  68. onTouchMove = (event: GestureResponderEventWithForce) => {
  69. clearTimeout(this.timeout);
  70. const { force, timestamp } = event.nativeEvent;
  71. const diff = (timestamp - this.ts);
  72. if (force > PREVIEW_MIN_FORCE && diff > PREVIEW_DELAY) {
  73. TouchablePreview.peeking = true;
  74. if (typeof this.props.onPeekIn === 'function') {
  75. this.props.onPeekIn();
  76. }
  77. }
  78. this.timeout = setTimeout(this.onTouchEnd, PREVIEW_TIMEOUT);
  79. }
  80. onTouchEnd = () => {
  81. clearTimeout(this.timeout);
  82. TouchablePreview.peeking = false;
  83. if (typeof this.props.onPeekOut === 'function') {
  84. this.props.onPeekOut();
  85. }
  86. }
  87. render() {
  88. const { children, touchableComponent, onPress, onPressIn, ...props } = this.props;
  89. // Default to TouchableWithoutFeedback for iOS if set to TouchableNativeFeedback
  90. const Touchable = (
  91. Platform.OS === 'ios' && touchableComponent instanceof TouchableNativeFeedback
  92. ? TouchableWithoutFeedback
  93. : touchableComponent
  94. ) as typeof TouchableWithoutFeedback;
  95. // Wrap component with Touchable for handling platform touches
  96. // and a single react View for detecting force and timing.
  97. return (
  98. <Touchable
  99. ref={this.onRef}
  100. onPress={this.onPress}
  101. onPressIn={this.onPressIn}
  102. {...props}
  103. >
  104. <View
  105. onTouchStart={this.onTouchStart}
  106. onTouchMove={this.onTouchMove as (event: GestureResponderEvent) => void}
  107. onTouchEnd={this.onTouchEnd}
  108. >
  109. {children}
  110. </View>
  111. </Touchable>
  112. );
  113. }
  114. }