forked from wonday/react-native-pdf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDoubleTapView.js
97 lines (84 loc) · 3.25 KB
/
DoubleTapView.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
'use strict'
import React, { useRef } from 'react'
import { View, PanResponder } from 'react-native'
import PropTypes from 'prop-types'
import { ViewPropTypes } from 'deprecated-react-native-prop-types'
const DoubleTapView = (props) => {
const prevTouchInfo = useRef({
prevTouchX: 0,
prevTouchY: 0,
prevTouchTimeStamp: 0
})
const timer = useRef(null)
const gestureHandlers = useRef(
PanResponder.create({
onStartShouldSetPanResponder: (e, gestureState) => gestureState.numberActiveTouches === 1,
onStartShouldSetResponderCapture: (e, gestureState) => gestureState.numberActiveTouches === 1,
onMoveShouldSetPanResponder: (e, gestureState) => false,
onMoveShouldSetResponderCapture: (e, gestureState) => false,
onPanResponderTerminationRequest: (e, gestureState) => false,
onPanResponderRelease: handlePanResponderRelease
})
).current
const distance = (x0, y0, x1, y1) => {
return Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)).toFixed(1)
}
const isDoubleTap = (currentTouchTimeStamp, { x0, y0 }) => {
const { prevTouchX, prevTouchY, prevTouchTimeStamp } = prevTouchInfo.current
const dt = currentTouchTimeStamp - prevTouchTimeStamp
const { delay, radius } = props
return prevTouchTimeStamp > 0 && dt < delay && distance(prevTouchX, prevTouchY, x0, y0) < radius
}
const handlePanResponderRelease = (evt, gestureState) => {
const currentTouchTimeStamp = Date.now()
const x = evt.nativeEvent.locationX
const y = evt.nativeEvent.locationY
if (timer.current) {
if (isDoubleTap(currentTouchTimeStamp, gestureState)) {
clearTimeout(timer.current)
timer.current = null
props?.onDoubleTap()
} else {
const { prevTouchX, prevTouchY, prevTouchTimeStamp } = prevTouchInfo
const { radius } = props
// if not in radius, it's a move
if (distance(prevTouchX, prevTouchY, gestureState.x0, gestureState.y0) < radius) {
timer.current = null
props?.onSingleTap(x, y)
}
}
} else {
// do not count scroll gestures as taps
if (distance(0, gestureState.dx, 0, gestureState.dy) < 10) {
timer.current = setTimeout(() => {
props?.onSingleTap(x, y)
timer.current = null
}, props?.delay)
}
}
prevTouchInfo.current = {
prevTouchX: gestureState.x0,
prevTouchY: gestureState.y0,
prevTouchTimeStamp: currentTouchTimeStamp
}
}
DoubleTapView.propTypes = {
...ViewPropTypes,
delay: PropTypes.number,
radius: PropTypes.number,
onSingleTap: PropTypes.func,
onDoubleTap: PropTypes.func
}
DoubleTapView.defaultProps = {
delay: 300,
radius: 50,
onSingleTap: () => {},
onDoubleTap: () => {}
}
return (
<View {...props} {...gestureHandlers?.panHandlers}>
{props?.children}
</View>
)
}
export default DoubleTapView