react-native#PanResponder TypeScript Examples
The following examples show how to use
react-native#PanResponder.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CircularSlider.tsx From nyxo-app with GNU General Public License v3.0 | 5 votes |
constructor(props: CircularSliderProps) {
super(props)
this._sleepPanResponder = PanResponder.create({
onMoveShouldSetPanResponder: (_evt, _gestureState) => true,
onMoveShouldSetPanResponderCapture: (_evt, _gestureState) => true,
onPanResponderGrant: (_evt, _gestureState) => this.setCircleCenter(),
onPanResponderMove: (_evt, { moveX, moveY }) => {
const { circleCenterX, circleCenterY } = this.state
const { angleLength, startAngle, onUpdate } = this.props
const currentAngleStop = (startAngle + angleLength) % (2 * Math.PI)
let newAngle =
Math.atan2(moveY - circleCenterY, moveX - circleCenterX) + Math.PI / 2
if (newAngle < 0) {
newAngle += 2 * Math.PI
}
let newAngleLength = currentAngleStop - newAngle
if (newAngleLength < 0) {
newAngleLength += 2 * Math.PI
}
onUpdate({
startAngle: newAngle,
angleLength: newAngleLength % (2 * Math.PI)
})
}
})
this._wakePanResponder = PanResponder.create({
onMoveShouldSetPanResponder: (_evt, _gestureState) => true,
onMoveShouldSetPanResponderCapture: (_evt, _gestureState) => true,
onPanResponderGrant: (_evt, _gestureState) => this.setCircleCenter(),
onPanResponderMove: (_evt, { moveX, moveY }) => {
const { circleCenterX, circleCenterY } = this.state
const { angleLength, startAngle, onUpdate } = this.props
const newAngle =
Math.atan2(moveY - circleCenterY, moveX - circleCenterX) + Math.PI / 2
let newAngleLength = (newAngle - startAngle) % (2 * Math.PI)
if (newAngleLength < 0) {
newAngleLength += 2 * Math.PI
}
onUpdate({ startAngle, angleLength: newAngleLength })
}
})
}
Example #2
Source File: CircularSlider.tsx From nyxo-app with GNU General Public License v3.0 | 5 votes |
_wakePanResponder: PanResponder
Example #3
Source File: CircularSlider.tsx From nyxo-app with GNU General Public License v3.0 | 5 votes |
_sleepPanResponder: PanResponder
Example #4
Source File: IterableInboxMessageCell.tsx From react-native-sdk with MIT License | 4 votes |
IterableInboxMessageCell = ({
index,
last,
dataModel,
rowViewModel,
customizations,
swipingCheck,
messageListItemLayout,
deleteRow,
handleMessageSelect,
contentWidth,
isPortrait
}: MessageCellProps) => {
const position = useRef(new Animated.ValueXY()).current
let deleteSliderHeight = customizations.messageRow?.height ? customizations.messageRow.height: 150
if(messageListItemLayout(last, rowViewModel)) {
deleteSliderHeight = messageListItemLayout(last, rowViewModel)[1]
}
const styles = StyleSheet.create({
textContainer: {
width: '100%',
elevation: 2
},
deleteSlider: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-end',
paddingRight: 10,
backgroundColor: 'red',
position: 'absolute',
elevation: 1,
width: '100%',
height: deleteSliderHeight
},
textStyle: {
fontWeight: 'bold',
fontSize: 15,
color: 'white'
}
})
let { textContainer, deleteSlider, textStyle } = styles
deleteSlider = (isPortrait) ? deleteSlider : { ...deleteSlider, paddingRight: 40 }
const scrollThreshold = contentWidth / 15
const FORCING_DURATION = 350
//If user swipes, either complete swipe or reset
function userSwipedLeft(gesture: any) {
if (gesture.dx < -0.6 * contentWidth) {
completeSwipe()
} else {
resetPosition()
}
}
function completeSwipe() {
const x = -2000
Animated.timing(position, {
toValue: { x, y: 0 },
duration: FORCING_DURATION,
useNativeDriver: false
}).start(() => deleteRow(rowViewModel.inAppMessage.messageId))
}
function resetPosition() {
Animated.timing(position, {
toValue: { x: 0, y: 0 },
duration: 200,
useNativeDriver: false
}).start()
}
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => false,
onMoveShouldSetPanResponder: (event, gestureState) => {
const { dx, dy } = gestureState
// return true if user is swiping, return false if it's a single click
return Math.abs(dx) !== 0 && Math.abs(dy) !== 0
},
onMoveShouldSetPanResponderCapture: (event, gestureState) => {
const { dx, dy } = gestureState
// return true if user is swiping, return false if it's a single click
return Math.abs(dx) !== 0 && Math.abs(dy) !== 0
},
onPanResponderTerminationRequest: () => false,
onPanResponderGrant: () => {
position.setValue({ x: 0, y: 0 })
},
onPanResponderMove: (event, gesture) => {
if (gesture.dx <= -scrollThreshold) {
//enables swipeing when threshold is reached
swipingCheck(true)
//threshold value is deleted from movement
const x = gesture.dx
//position is set to the new value
position.setValue({ x, y: 0 })
}
},
onPanResponderRelease: (event, gesture) => {
position.flattenOffset()
if (gesture.dx < 0) {
userSwipedLeft(gesture)
}
else {
resetPosition();
}
swipingCheck(false)
}
})
).current
return (
<>
<View style={deleteSlider}>
<Text style={textStyle}>DELETE</Text>
</View>
<Animated.View
style={[textContainer, position.getLayout()]}
{...panResponder.panHandlers}
>
<TouchableOpacity
activeOpacity={1}
onPress={() => {
handleMessageSelect(rowViewModel.inAppMessage.messageId, index)
}}
>
{messageListItemLayout(last, rowViewModel) ?
messageListItemLayout(last, rowViewModel)[0] :
defaultMessageListLayout(last, dataModel, rowViewModel, customizations, isPortrait)}
</TouchableOpacity>
</Animated.View>
</>
)
}
Example #5
Source File: drag.ts From keen-slider with MIT License | 4 votes |
export default function Drag(
slider: SliderInstance<
NativeOptions,
NativeInstance<{}>,
| HOOK_DRAG_ENDED
| HOOK_DRAG_STARTED
| HOOK_DRAGGED
| HOOK_UPDATED
| HOOK_LAYOUT_CHANGED
| HOOK_DRAG_CHECKED
>
): void {
const breakFactorValue = 2
let direction
let defaultDirection
let size
let dragActive
let dragSpeed
let dragIdentifier
let dragJustStarted
let lastValue
let lastX
let lastY
let min
let max
function dragStart(e) {
if (
dragActive ||
!slider.track.details ||
!slider.track.details.length ||
!slider.options.drag
)
return
dragActive = true
dragJustStarted = true
dragIdentifier = e.idChanged
isSlide(e)
lastValue = xy(e)
slider.emit('dragStarted')
return true
}
function drag(e) {
if (!dragActive || dragIdentifier !== e.idChanged) {
return
}
const value = xy(e)
if (dragJustStarted) {
if (!isSlide(e)) return dragStop(e)
slider.emit('dragChecked')
dragJustStarted = false
}
const distance = rubberband(
(dragSpeed(lastValue - value) / slider.size) * defaultDirection
)
direction = sign(distance)
slider.track.add(distance)
lastValue = value
slider.emit('dragged')
}
function setSpeed() {
const speed = slider.options.dragSpeed || 1
dragSpeed =
typeof speed === 'function' ? speed : val => val * (speed as number)
}
function dragStop(e) {
if (!dragActive || dragIdentifier !== e.idChanged) return
dragActive = false
slider.emit('dragEnded')
}
function isSlide(e) {
const vertical = slider.options.vertical
const x = vertical ? e.y : e.x
const y = vertical ? e.x : e.y
const isSlide =
lastX !== undefined &&
lastY !== undefined &&
Math.abs(lastY - y) <= Math.abs(lastX - x)
lastX = x
lastY = y
return isSlide
}
function rubberband(distance) {
if (min === -Infinity && max === Infinity) return distance
const details = slider.track.details
const length = details.length
const position = details.position
const clampedDistance = clamp(distance, min - position, max - position)
if (length === 0) return 0
if (!slider.options.rubberband) {
return clampedDistance
}
if (position <= max && position >= min) return distance
if (
(position < min && direction > 0) ||
(position > max && direction < 0)
) {
return distance
}
const overflow = (position < min ? position - min : position - max) / length
const trackSize = size * length
const overflowedSize = Math.abs(overflow * trackSize)
const p = Math.max(0, 1 - (overflowedSize / size) * breakFactorValue)
return p * p * distance
}
function setSizes() {
size = slider.size
const details = slider.track.details
if (!details) return
min = details.min
max = details.max
}
function xy(e) {
return slider.options.vertical ? e.y : e.x
}
function update() {
setSizes()
setSpeed()
defaultDirection = !slider.options.rtl ? 1 : -1
}
slider.on('updated', update)
slider.on('layoutChanged', update)
slider.on('created', update)
const pan = PanResponder.create({
onPanResponderMove: inputHandler(drag),
onPanResponderRelease: inputHandler(dragStop),
onPanResponderTerminate: inputHandler(dragStop),
onStartShouldSetPanResponder: inputHandler(dragStart),
})
Object.assign(slider.containerProps, pan.panHandlers)
}
Example #6
Source File: AnalogClock.tsx From react-native-paper-dates with MIT License | 4 votes |
function AnalogClock({
hours,
minutes,
focused,
is24Hour,
onChange,
}: {
hours: number
minutes: number
focused: PossibleClockTypes
is24Hour: boolean
onChange: (hoursMinutesAndFocused: {
hours: number
minutes: number
focused?: undefined | PossibleClockTypes
}) => any
}) {
const theme = useTheme()
const { mode } = React.useContext(DisplayModeContext)
// used to make pointer shorter if hours are selected and above 12
const shortPointer = (hours === 0 || hours > 12) && is24Hour
const clockRef = React.useRef<View | null>(null)
// Hooks are nice, sometimes... :-)..
// We need the latest values, since the onPointerMove uses a closure to the function
const hoursRef = useLatest(hours)
const onChangeRef = useLatest(onChange)
const minutesRef = useLatest(minutes)
const focusedRef = useLatest(focused)
const is24HourRef = useLatest(is24Hour)
const modeRef = useLatest(mode)
const onPointerMove = React.useCallback(
(e: GestureResponderEvent, final: boolean) => {
let x = e.nativeEvent.locationX
let y = e.nativeEvent.locationY
let angle = getAngle(x, y, circleSize)
if (focusedRef.current === clockTypes.hours) {
let hours24 = is24HourRef.current
let previousHourType = getHourType(hoursRef.current)
let pickedHours = getHours(angle, previousHourType)
let hours12AndPm = !hours24 && modeRef.current === 'AM'
let hourTypeFromOffset = getHourTypeFromOffset(x, y, circleSize)
let hours24AndPM = hours24 && hourTypeFromOffset === hourTypes.pm
// Avoiding the "24h"
// Should be 12h for 12 hours and PM mode
if (hours12AndPm || hours24AndPM) {
pickedHours += 12
}
if (modeRef.current === 'AM' && pickedHours === 12) {
pickedHours = 0
}
if (
(!hours24 && modeRef.current === 'AM' && pickedHours === 12) ||
pickedHours === 24
) {
pickedHours = 0
}
if (hoursRef.current !== pickedHours || final) {
onChangeRef.current({
hours: pickedHours,
minutes: minutesRef.current,
focused: final ? clockTypes.minutes : undefined,
})
}
} else if (focusedRef.current === clockTypes.minutes) {
let pickedMinutes = getMinutes(angle)
if (minutesRef.current !== pickedMinutes) {
onChangeRef.current({
hours: hoursRef.current,
minutes: pickedMinutes,
})
}
}
},
[focusedRef, is24HourRef, hoursRef, onChangeRef, minutesRef, modeRef]
)
const panResponder = React.useRef(
PanResponder.create({
onPanResponderGrant: (e) => onPointerMove(e, false),
onPanResponderMove: (e) => onPointerMove(e, false),
onPanResponderRelease: (e) => onPointerMove(e, true),
onStartShouldSetPanResponder: returnTrue,
onStartShouldSetPanResponderCapture: () => false,
onMoveShouldSetPanResponder: returnTrue,
onMoveShouldSetPanResponderCapture: returnTrue,
onPanResponderTerminationRequest: returnTrue,
onShouldBlockNativeResponder: returnTrue,
})
).current
const dynamicSize = focused === clockTypes.hours && shortPointer ? 33 : 0
const pointerNumber = focused === clockTypes.hours ? hours : minutes
const degreesPerNumber = focused === clockTypes.hours ? 30 : 6
return (
<View
ref={clockRef}
{...panResponder.panHandlers}
style={[
styles.clock,
{
backgroundColor: theme.dark
? Color(theme.colors.surface).lighten(1.2).hex()
: Color(theme.colors.surface).darken(0.1).hex(),
},
]}
// @ts-ignore -> https://github.com/necolas/react-native-web/issues/506
cursor={'pointer'}
>
<View
style={[
styles.line,
{
backgroundColor: theme.colors.primary,
transform: [
{ rotate: -90 + pointerNumber * degreesPerNumber + 'deg' },
{
translateX: circleSize / 4 - 4 - dynamicSize / 2,
},
],
width: circleSize / 2 - 4 - dynamicSize,
},
]}
pointerEvents="none"
>
<View
style={[styles.endPoint, { backgroundColor: theme.colors.primary }]}
/>
</View>
<View
style={[StyleSheet.absoluteFill, styles.center]}
pointerEvents="none"
>
<View
style={[
styles.middlePoint,
{
backgroundColor: theme.colors.primary,
},
]}
/>
</View>
<AnimatedClockSwitcher
focused={focused}
hours={<AnalogClockHours is24Hour={is24Hour} hours={hours} />}
minutes={<AnalogClockMinutes minutes={minutes} />}
/>
</View>
)
}