react-native-gesture-handler#PanGestureHandler JavaScript Examples
The following examples show how to use
react-native-gesture-handler#PanGestureHandler.
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: index.js From discovery-mobile-ui with MIT License | 6 votes |
Catalog = ({
collection, selectedRecordsGroupedByType, navigation, timelineIntervals,
}) => {
const noRecords = timelineIntervals.recordCount === 0;
return (
<PanGestureHandler
activeOffsetX={-10}
failOffsetX={[-20, 0]}
onGestureEvent={() => navigation.navigate('CollectionDetails')}
>
<View style={styles.drawerContainer}>
<FilterDrawer>
<CatalogScreenHeader collection={collection} navigation={navigation} />
<Timeline noRecords={noRecords} />
{noRecords && (
<View style={styles.zeroStateContainer}>
<Text style={styles.zeroStateText}>
No Records available based on the Filters or the time interval.
</Text>
</View>
)}
{!noRecords && (
<>
<ResourceTypePicker />
<ScrollView style={styles.scrollView}>
<SubTypeAccordionsContainer data={selectedRecordsGroupedByType} />
</ScrollView>
</>
)}
</FilterDrawer>
</View>
</PanGestureHandler>
);
}
Example #2
Source File: BottomSheet.js From actual with MIT License | 5 votes |
render() {
const { children, flush } = this.props;
return (
<View style={styles.container} ref={el => (this.container = el)}>
<PanGestureHandler
ref={this.drawerHandler}
onGestureEvent={this.panEvent}
onHandlerStateChange={this.onHandlerStateChange}
>
<Animated.View style={{ flex: 1 }}>
<Animated.View
style={[
styles.darkened,
{
backgroundColor: 'rgba(0, 0, 0, 1.0)',
opacity: this.translateY.interpolate({
inputRange: [0, windowHeight],
outputRange: [0.5, 0]
})
}
]}
/>
<Animated.View
style={{
flex: 1,
borderTopLeftRadius: 4,
borderTopRightRadius: 4,
backgroundColor: '#f0f0f0',
opacity: this.opacity,
transform: [
{
translateY: this.translateY.interpolate({
inputRange: [0, windowHeight],
outputRange: [0, windowHeight],
extrapolate: 'clamp'
})
}
]
}}
>
<View style={[styles.content, !flush && { paddingTop: 15 }]}>
{typeof children === 'function'
? children({
panEvent: this.panEvent,
onHandlerStateChange: this.onHandlerStateChange
})
: children}
</View>
<View style={styles.header}>
<View style={styles.closeHandle} />
</View>
</Animated.View>
</Animated.View>
</PanGestureHandler>
</View>
);
}
Example #3
Source File: ScrollableBottomSheet.js From actual with MIT License | 5 votes |
render() {
const { shouldCheckScrollPan, forcedHeight } = this.state;
const {
renderHeader,
renderScroll = this.defaultRenderScroll
} = this.props;
return (
<BottomSheet
ref={el => (this.sheet = el)}
onMove={this.onMove}
{...this.props}
>
{({ panEvent, onHandlerStateChange }) => {
return (
<View style={{ flex: 1 }}>
{renderHeader && renderHeader()}
<PanGestureHandler
ref={this.checkScrollHandler}
enabled={shouldCheckScrollPan}
activeOffsetY={20}
failOffsetY={[-1, 10000]}
onGestureEvent={panEvent}
onHandlerStateChange={onHandlerStateChange}
simultaneousHandlers={this.scrollWrapperHandler}
>
<Animated.View style={{ flex: 1 }}>
<PanGestureHandler
ref={this.scrollWrapperHandler}
simultaneousHandlers={[
this.scrollHandler,
this.checkScrollHandler
]}
onGestureEvent={this.onScrollPan}
>
<View
style={
forcedHeight
? { flex: 1, paddingBottom: forcedHeight }
: { flex: 1 }
}
>
<NativeViewGestureHandler
ref={this.scrollHandler}
simultaneousHandlers={this.scrollWrapperHandler}
{...(shouldCheckScrollPan
? { waitFor: this.checkScrollHandler }
: {})}
>
{renderScroll({
ref: el => (this.scrollView = el),
automaticallyAdjustContentInsets: false,
onScrollBeginDrag: this.onScrollBeginDrag,
onScrollEndDrag: this.onScrollEndDrag,
onScroll: this.onScroll,
onMomentumScrollEnd: this.onMomentumScrollEnd,
scrollEventThrottle: 1
})}
</NativeViewGestureHandler>
</View>
</PanGestureHandler>
</Animated.View>
</PanGestureHandler>
</View>
);
}}
</BottomSheet>
);
}
Example #4
Source File: budget.js From actual with MIT License | 4 votes |
render() {
const {
type,
categoryGroups,
month,
monthBounds,
editMode,
refreshControl,
onPrevMonth,
onNextMonth,
onAddCategory,
onReorderCategory,
onReorderGroup,
onShowBudgetDetails,
onOpenActionSheet,
onBudgetAction
} = this.props;
let { editingCategory } = this.state;
let currentMonth = monthUtils.currentMonth();
return (
<NamespaceContext.Provider value={monthUtils.sheetForMonth(month, type)}>
<View
style={{ flex: 1, backgroundColor: 'white' }}
data-testid="budget-table"
>
<BudgetHeader
currentMonth={month}
monthBounds={monthBounds}
editMode={editMode}
onDone={() => this.props.onEditMode(false)}
onOpenActionSheet={onOpenActionSheet}
onPrevMonth={onPrevMonth}
onNextMonth={onNextMonth}
/>
<View
style={{
flexDirection: 'row',
paddingHorizontal: 10,
paddingVertical: 10,
paddingRight: 14,
backgroundColor: 'white',
borderBottomWidth: 1,
borderColor: colors.n9
}}
>
{type === 'report' ? (
<Saved projected={month >= currentMonth} />
) : (
<ToBudget
toBudget={rolloverBudget.toBudget}
onPress={onShowBudgetDetails}
/>
)}
<View style={{ flex: 1, zIndex: -1 }} />
<View style={{ width: 90 }}>
<Label title="BUDGETED" style={{ color: colors.n1 }} />
<CellValue
binding={reportBudget.totalBudgetedExpense}
type="financial"
style={[
styles.smallText,
{ color: colors.n1, textAlign: 'right', fontWeight: '500' }
]}
formatter={(value) => {
return format(-parseFloat(value || '0'), 'financial');
}}
/>
</View>
<View style={{ width: 90 }}>
<Label title="BALANCE" style={{ color: colors.n1 }} />
<CellValue
binding={rolloverBudget.totalBalance}
type="financial"
style={[
styles.smallText,
{ color: colors.n1, textAlign: 'right', fontWeight: '500' }
]}
/>
</View>
</View>
<AndroidKeyboardAvoidingView includeStatusBar={true}>
{!editMode ? (
<ScrollView
ref={(el) => (this.list = el)}
keyboardShouldPersistTaps="always"
refreshControl={refreshControl}
style={{ backgroundColor: colors.n10 }}
automaticallyAdjustContentInsets={false}
>
<BudgetGroups
type={type}
categoryGroups={categoryGroups}
editingId={editingCategory}
editMode={editMode}
gestures={this.gestures}
month={month}
onEditCategory={this.onEditCategory}
onAddCategory={onAddCategory}
onReorderCategory={onReorderCategory}
onReorderGroup={onReorderGroup}
onBudgetAction={onBudgetAction}
/>
</ScrollView>
) : (
<DragDrop>
{({
dragging,
onGestureEvent,
onHandlerStateChange,
scrollRef,
onScroll
}) => (
<NativeViewGestureHandler
enabled={!dragging}
waitFor={this.gestures.pan}
ref={this.gestures.scroll}
>
<Animated.ScrollView
ref={(el) => {
scrollRef.current = el;
this.list = el;
}}
onScroll={onScroll}
keyboardShouldPersistTaps="always"
scrollEventThrottle={16}
scrollEnabled={!dragging}
style={{ backgroundColor: colors.n10 }}
>
<PanGestureHandler
avgTouches
minDeltaX={2}
minDeltaY={2}
maxPointers={1}
onGestureEvent={onGestureEvent}
onHandlerStateChange={onHandlerStateChange}
ref={this.gestures.pan}
waitFor={this.gestures.scroll}
>
<Animated.View>
<BudgetGroups
categoryGroups={categoryGroups}
editingId={editingCategory}
editMode={editMode}
gestures={this.gestures}
onEditCategory={this.onEditCategory}
onAddCategory={onAddCategory}
onReorderCategory={onReorderCategory}
onReorderGroup={onReorderGroup}
/>
</Animated.View>
</PanGestureHandler>
<DragDropHighlight />
</Animated.ScrollView>
</NativeViewGestureHandler>
)}
</DragDrop>
)}
</AndroidKeyboardAvoidingView>
</View>
</NamespaceContext.Provider>
);
}
Example #5
Source File: ChildEdit.js From actual with MIT License | 4 votes |
render() {
const { transaction, exiting, getCategoryName, amountSign } = this.props;
return (
<View
style={{
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
justifyContent: 'flex-end'
}}
pointerEvents={exiting ? 'none' : 'auto'}
>
<Animated.View
style={{
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
backgroundColor: 'black',
opacity: this.gestureY.interpolate({
inputRange: [0, 400],
outputRange: [0.4, 0],
extrapolate: 'clamp'
})
}}
/>
<PanGestureHandler
onGestureEvent={this.gestureEvent}
onHandlerStateChange={this.onHandlerStateChange}
>
<Animated.View
style={{
justifyContent: 'flex-end',
backgroundColor: 'white',
margin: 10,
borderRadius: 4,
overflow: 'hidden',
transform: [{ translateY: this.gestureY }]
}}
>
<View
style={{
borderBottomWidth: 1,
borderColor: '#f0f0f0',
flexDirection: 'row',
justifyContent: 'center',
padding: 15
}}
>
<Text style={mobileStyles.header.headerTitleStyle}>
Edit Split Transaction
</Text>
</View>
<View
style={{
backgroundColor: '#FBFCFC'
}}
>
<View style={{ alignItems: 'center', marginVertical: 15 }}>
<FieldLabel
title="Amount"
flush
style={{ marginBottom: 0, paddingLeft: 0 }}
/>
<FocusableAmountInput
value={transaction.amount}
sign={amountSign}
style={{ height: 26, transform: [] }}
focusedStyle={{
width: 'auto',
paddingVertical: 0,
paddingHorizontal: 10,
minWidth: 100,
transform: [{ translateY: -0.5 }]
}}
onBlur={value =>
this.props.onEdit(transaction, 'amount', value.toString())
}
textStyle={{ fontSize: 20, textAlign: 'center' }}
/>
</View>
<FieldLabel title="Category" flush />
<TapField
value={getCategoryName(transaction.category)}
onTap={this.onEditCategory}
/>
<FieldLabel title="Notes" />
<InputField
defaultValue={transaction.notes}
multiline={true}
numberOfLines={10}
style={{ height: 60, marginBottom: 25 }}
paddingTop={10}
paddingBottom={10}
onUpdate={value =>
this.props.onEdit(transaction, 'notes', value)
}
/>
</View>
</Animated.View>
</PanGestureHandler>
</View>
);
}
Example #6
Source File: PatternLock.js From react-native-pattern-lock with MIT License | 4 votes |
export function PatternLock(props) { const [isError, setIsError] = useState(false); const canTouch = useSharedValue(true); const patternPoints = useSharedValue(); const selectedIndexes = useSharedValue([]); const endPoint = useSharedValue(); const containerLayout = useSharedValue({ width: 0, height: 0, min: 0 }); const R = useDerivedValue( () => (containerLayout.value.min / props.rowCount - props.patternMargin * 2) / 2 ); const cvc = useAnimatedStyle(() => ({ flexDirection: "row", flexWrap: "wrap", marginBottom: `${ Math.max( 0, containerLayout.value.height / containerLayout.value.width - 1.25 ) * 50 }%`, width: containerLayout.value.min, height: containerLayout.value.min, })); const msgX = useSharedValue(0); const msgColor = { color: isError ? props.errorColor : props.activeColor }; const msgStyle = useAnimatedStyle(() => { return { transform: [{ translateX: msgX.value }] }; }); const onContainerLayout = ({ nativeEvent: { layout: { x, y, width, height }, }, }) => (containerLayout.value = { width, height, min: Math.min(width, height), }); const onPatternLayout = ({ nativeEvent: { layout } }) => { const points = []; for (let i = 0; i < props.rowCount; i++) { for (let j = 0; j < props.columnCount; j++) { points.push({ x: layout.x + (layout.width / props.columnCount) * (j + 0.5), y: layout.y + (layout.height / props.rowCount) * (i + 0.5), }); } } patternPoints.value = points; }; const onEndJS = (res) => { if (props.onCheck) { canTouch.value = false; if (!props.onCheck(res)) { setIsError(true); const closeError = () => setIsError(false); runOnUI(() => { cancelAnimation(msgX); //修复iOS上原地spring不动的问题。 msgX.value = withSpring( msgX.value === 0 ? 0.1 : 0, { stiffness: 2000, damping: 10, mass: 1, velocity: 2000, }, (finished) => { runOnJS(closeError)(); canTouch.value = true; selectedIndexes.value = []; } ); })(); } else { setIsError(false); setTimeout(() => { selectedIndexes.value = []; canTouch.value = true; }, 1000); } } }; const panHandler = useAnimatedGestureHandler({ onStart: (evt) => { if ( canTouch.value && patternPoints.value && selectedIndexes.value.length === 0 ) { const selected = []; patternPoints.value.every((p, idx) => { if ( (p.x - evt.x) * (p.x - evt.x) + (p.y - evt.y) * (p.y - evt.y) < R.value * R.value ) { selected.push(idx); return false; } return true; }); selectedIndexes.value = selected; } }, onActive: (evt) => { if ( canTouch.value && patternPoints.value && selectedIndexes.value.length > 0 ) { patternPoints.value.every((p, idx) => { if ( (p.x - evt.x) * (p.x - evt.x) + (p.y - evt.y) * (p.y - evt.y) < R.value * R.value ) { if (selectedIndexes.value.indexOf(idx) < 0) { selectedIndexes.value = [...selectedIndexes.value, idx]; } return false; } return true; }); endPoint.value = { x: evt.x, y: evt.y }; } }, onEnd: (evt) => { if (!canTouch.value) return; endPoint.value = null; if (selectedIndexes.value.length > 0) runOnJS(onEndJS)(selectedIndexes.value.join("")); }, }); const animatedProps = useAnimatedProps(() => { let d = ""; selectedIndexes.value.forEach((idx) => { d += !d ? " M" : " L"; d += ` ${patternPoints.value[idx].x},${patternPoints.value[idx].y}`; }); if (d && endPoint.value) d += ` L${endPoint.value.x},${endPoint.value.y}`; if (!d) d = "M-1,-1"; return { d }; }); return ( <PanGestureHandler onGestureEvent={panHandler}> <Animated.View style={styles.container} onLayout={onContainerLayout}> <TapGestureHandler onGestureEvent={panHandler}> <Animated.View style={styles.container}> <View style={styles.msgc}> <Animated.Text style={[msgColor, msgStyle]}> {props.message} </Animated.Text> </View> <Animated.View style={cvc} onLayout={onPatternLayout}> {Array(props.rowCount * props.columnCount) .fill(0) .map((_, idx) => { const patternColor = useDerivedValue(() => { if (selectedIndexes.value.findIndex((v) => v === idx) < 0) { return props.inactiveColor; } else if (isError) { return props.errorColor; } else { return props.activeColor; } }); const outer = useAnimatedStyle(() => { return { borderWidth: 2, width: 2 * R.value, height: 2 * R.value, alignItems: "center", justifyContent: "center", borderColor: patternColor.value, borderRadius: 2 * R.value, margin: props.patternMargin, }; }); const inner = useAnimatedStyle(() => { return { width: R.value * 0.8, height: R.value * 0.8, borderRadius: R.value * 0.8, backgroundColor: patternColor.value, }; }); return ( <Animated.View key={idx} style={outer}> <Animated.View style={inner} /> </Animated.View> ); })} </Animated.View> <Svg style={styles.svg} width="100%" height="100%"> <AnimatedPath fill="none" strokeWidth={3} animatedProps={animatedProps} stroke={isError ? props.errorColor : props.activeColor} /> </Svg> </Animated.View> </TapGestureHandler> </Animated.View> </PanGestureHandler> ); }
Example #7
Source File: index.js From interface-nubank with MIT License | 4 votes |
export default function Main() {
let offset = 0;
const translateY = new Animated.Value(0);
const animatedEvent = Animated.event(
[
{
nativeEvent: {
translationY: translateY,
},
},
],
{ useNativeDriver: true },
);
function onHandlerStateChanged(event) {
if (event.nativeEvent.oldState === State.ACTIVE) {
let opened = false;
const { translationY } = event.nativeEvent;
offset += translationY;
if (translationY >= 100) {
opened = true;
} else {
translateY.setValue(offset);
translateY.setOffset(0);
offset = 0;
}
Animated.timing(translateY, {
toValue: opened ? 380 : 0,
duration: 200,
useNativeDriver: true,
}).start(() => {
offset = opened ? 380 : 0;
translateY.setOffset(offset);
translateY.setValue(0);
});
}
}
return (
<SafeAreaView>
<Container>
<Header />
<Content>
<Menu translateY={translateY} />
<PanGestureHandler
onGestureEvent={animatedEvent}
onHandlerStateChange={onHandlerStateChanged}
>
<Card style={{
transform: [{
translateY: translateY.interpolate({
inputRange: [-350, 0, 380],
outputRange: [-50, 0, 380],
extrapolate: 'clamp',
}),
}],
}}
>
<CardHeader>
<Icon name="attach-money" size={28} color="#666" />
<Icon name="visibility-off" size={28} color="#666" />
</CardHeader>
<CardContent>
<Title>Saldo disponível</Title>
<Description>R$ 197.611,65</Description>
</CardContent>
<CardFooter>
<Annotation>
Transferência de R$ 20,00 recebida de Diego Schell Fernandes hoje às 06:00h
</Annotation>
</CardFooter>
</Card>
</PanGestureHandler>
</Content>
<Tabs translateY={translateY} />
</Container>
</SafeAreaView>
);
}
Example #8
Source File: index.js From openweathermap-reactnative with MIT License | 4 votes |
export default function ForecastDetails() {
let offset = 0;
const translateY = new Animated.Value(0);
const animatedEvent = Animated.event(
[
{
nativeEvent: {
translationY: translateY,
},
},
],
{useNativeDriver: true},
);
function onHandlerStateChanged(event) {
if (event.nativeEvent.oldState === State.ACTIVE) {
const {translationY} = event.nativeEvent;
let opened = false;
offset += translationY;
if (translationY >= 100) {
opened = true;
} else {
translateY.setValue(offset);
translateY.setOffset(0);
offset = 0;
}
Animated.timing(translateY, {
toValue: opened ? 500 : 0,
duration: 300,
useNativeDriver: true,
}).start(() => {
offset = opened ? 500 : 0;
translateY.setOffset(offset);
translateY.setValue(0);
});
}
}
return (
<PanGestureHandler
onGestureEvent={animatedEvent}
onHandlerStateChange={onHandlerStateChanged}>
<Card
style={{
transform: [
{
translateY: translateY.interpolate({
inputRange: [-300, 0, 500],
outputRange: [-30, 0, 620],
extrapolate: 'clamp',
}),
},
],
}}>
<Header
style={{
opacity: translateY.interpolate({
inputRange: [0, 400],
outputRange: [1, 0],
extrapolate: 'clamp',
}),
}}>
Vreeland
</Header>
<Body
style={{
opacity: translateY.interpolate({
inputRange: [0, 400],
outputRange: [1, 0],
extrapolate: 'clamp',
}),
}}>
<WeatherInfoContainer>
<Wind>M7º / L5º</Wind>
<Temperature>5º</Temperature>
<WeatherInfo>Light rain</WeatherInfo>
<Umidity>87 %</Umidity>
</WeatherInfoContainer>
<AnimationContainer>
<LottieView source={LottieAnimationJson} autoPlay loop />
</AnimationContainer>
</Body>
<Bottom>
<Observations>
Right now is 5ºC and feels like -1ºC outside. The wind is blowing
around 8.7 km/h and the pressure is 1009 hPa.
</Observations>
<BookmarkButton>
<ButtonText>Bookmark this location</ButtonText>
</BookmarkButton>
</Bottom>
</Card>
</PanGestureHandler>
);
}