0
# Advanced Layout Components
1
2
Sophisticated layout and interaction components for complex UI patterns like swipe-to-reveal and drawer layouts.
3
4
## Capabilities
5
6
### Swipeable
7
8
Component for creating swipe-to-reveal interfaces, commonly used in messaging apps and todo lists for contextual actions.
9
10
```typescript { .api }
11
/**
12
* Swipeable component for creating swipe-to-reveal interfaces
13
* Provides left and right swipe actions with customizable animations
14
*/
15
function Swipeable(props: {
16
friction?: number;
17
leftThreshold?: number;
18
rightThreshold?: number;
19
dragOffsetFromLeftEdge?: number;
20
dragOffsetFromRightEdge?: number;
21
overshootLeft?: boolean;
22
overshootRight?: boolean;
23
overshootFriction?: number;
24
onSwipeableLeftOpen?: () => void;
25
onSwipeableRightOpen?: () => void;
26
onSwipeableOpen?: (direction: "left" | "right") => void;
27
onSwipeableClose?: (direction: "left" | "right") => void;
28
onSwipeableLeftWillOpen?: () => void;
29
onSwipeableRightWillOpen?: () => void;
30
onSwipeableWillOpen?: (direction: "left" | "right") => void;
31
onSwipeableWillClose?: (direction: "left" | "right") => void;
32
renderLeftActions?: (
33
progressAnimatedValue: Animated.AnimatedAddition,
34
dragX: Animated.AnimatedAddition
35
) => React.ReactNode;
36
renderRightActions?: (
37
progressAnimatedValue: Animated.AnimatedAddition,
38
dragX: Animated.AnimatedAddition
39
) => React.ReactNode;
40
useNativeAnimations?: boolean;
41
animationOptions?: object;
42
containerStyle?: StyleProp<ViewStyle>;
43
childrenContainerStyle?: StyleProp<ViewStyle>;
44
enableTrackpadTwoFingerGesture?: boolean;
45
children: React.ReactNode;
46
}): JSX.Element;
47
48
interface SwipeableProps {
49
friction?: number;
50
leftThreshold?: number;
51
rightThreshold?: number;
52
dragOffsetFromLeftEdge?: number;
53
dragOffsetFromRightEdge?: number;
54
overshootLeft?: boolean;
55
overshootRight?: boolean;
56
overshootFriction?: number;
57
onSwipeableLeftOpen?: () => void;
58
onSwipeableRightOpen?: () => void;
59
onSwipeableOpen?: (direction: "left" | "right") => void;
60
onSwipeableClose?: (direction: "left" | "right") => void;
61
onSwipeableLeftWillOpen?: () => void;
62
onSwipeableRightWillOpen?: () => void;
63
onSwipeableWillOpen?: (direction: "left" | "right") => void;
64
onSwipeableWillClose?: (direction: "left" | "right") => void;
65
renderLeftActions?: (
66
progressAnimatedValue: Animated.AnimatedAddition,
67
dragX: Animated.AnimatedAddition
68
) => React.ReactNode;
69
renderRightActions?: (
70
progressAnimatedValue: Animated.AnimatedAddition,
71
dragX: Animated.AnimatedAddition
72
) => React.ReactNode;
73
useNativeAnimations?: boolean;
74
animationOptions?: object;
75
containerStyle?: StyleProp<ViewStyle>;
76
childrenContainerStyle?: StyleProp<ViewStyle>;
77
enableTrackpadTwoFingerGesture?: boolean;
78
children: React.ReactNode;
79
}
80
```
81
82
**Usage Example:**
83
84
```typescript
85
import React, { useRef } from "react";
86
import { View, Text, Animated, TouchableOpacity } from "react-native";
87
import { Swipeable } from "react-native-gesture-handler";
88
89
function SwipeableItem({ item, onDelete, onArchive }) {
90
const swipeableRef = useRef<Swipeable>(null);
91
92
const renderLeftActions = (progress, dragX) => {
93
const trans = dragX.interpolate({
94
inputRange: [0, 50, 100, 101],
95
outputRange: [-20, 0, 0, 1],
96
extrapolate: "clamp",
97
});
98
99
return (
100
<View style={{ flex: 1, backgroundColor: "green", justifyContent: "center" }}>
101
<Animated.View style={{ transform: [{ translateX: trans }] }}>
102
<TouchableOpacity
103
onPress={() => {
104
onArchive(item.id);
105
swipeableRef.current?.close();
106
}}
107
style={{ paddingHorizontal: 20 }}
108
>
109
<Text style={{ color: "white", fontWeight: "bold" }}>Archive</Text>
110
</TouchableOpacity>
111
</Animated.View>
112
</View>
113
);
114
};
115
116
const renderRightActions = (progress, dragX) => {
117
const trans = dragX.interpolate({
118
inputRange: [-101, -100, -50, 0],
119
outputRange: [1, 0, 0, 20],
120
extrapolate: "clamp",
121
});
122
123
return (
124
<View style={{ flex: 1, backgroundColor: "red", justifyContent: "center" }}>
125
<Animated.View style={{ transform: [{ translateX: trans }] }}>
126
<TouchableOpacity
127
onPress={() => {
128
onDelete(item.id);
129
swipeableRef.current?.close();
130
}}
131
style={{ paddingHorizontal: 20 }}
132
>
133
<Text style={{ color: "white", fontWeight: "bold" }}>Delete</Text>
134
</TouchableOpacity>
135
</Animated.View>
136
</View>
137
);
138
};
139
140
return (
141
<Swipeable
142
ref={swipeableRef}
143
renderLeftActions={renderLeftActions}
144
renderRightActions={renderRightActions}
145
leftThreshold={80}
146
rightThreshold={80}
147
friction={1.5}
148
>
149
<View style={{
150
padding: 15,
151
backgroundColor: "white",
152
borderBottomWidth: 1,
153
borderBottomColor: "#eee"
154
}}>
155
<Text>{item.title}</Text>
156
</View>
157
</Swipeable>
158
);
159
}
160
```
161
162
### Pressable
163
164
Modern pressable component using the new gesture API, providing advanced press handling with gesture coordination.
165
166
```typescript { .api }
167
/**
168
* Modern pressable component using the new gesture API
169
* Provides sophisticated press detection with gesture relationship management
170
*/
171
function Pressable(props: {
172
children?: React.ReactNode | ((state: PressableStateCallbackType) => React.ReactNode);
173
onPress?: (event?: GestureResponderEvent) => void;
174
onPressIn?: (event?: GestureResponderEvent) => void;
175
onPressOut?: (event?: GestureResponderEvent) => void;
176
onLongPress?: (event?: GestureResponderEvent) => void;
177
onHoverIn?: (event?: MouseEvent) => void;
178
onHoverOut?: (event?: MouseEvent) => void;
179
disabled?: boolean;
180
delayLongPress?: number;
181
hitSlop?: Insets;
182
pressRetentionOffset?: Insets;
183
android_disableSound?: boolean;
184
android_ripple?: AndroidRippleConfig;
185
testID?: string;
186
style?: StyleProp<ViewStyle> | ((state: PressableStateCallbackType) => StyleProp<ViewStyle>);
187
unstable_pressDelay?: number;
188
// Gesture Handler specific props
189
simultaneousWithExternalGesture?: GestureRef[];
190
requireExternalGestureToFail?: GestureRef[];
191
blocksExternalGesture?: GestureRef[];
192
}): JSX.Element;
193
194
interface PressableProps {
195
children?: React.ReactNode | ((state: PressableStateCallbackType) => React.ReactNode);
196
onPress?: (event?: GestureResponderEvent) => void;
197
onPressIn?: (event?: GestureResponderEvent) => void;
198
onPressOut?: (event?: GestureResponderEvent) => void;
199
onLongPress?: (event?: GestureResponderEvent) => void;
200
onHoverIn?: (event?: MouseEvent) => void;
201
onHoverOut?: (event?: MouseEvent) => void;
202
disabled?: boolean;
203
delayLongPress?: number;
204
hitSlop?: Insets;
205
pressRetentionOffset?: Insets;
206
android_disableSound?: boolean;
207
android_ripple?: AndroidRippleConfig;
208
testID?: string;
209
style?: StyleProp<ViewStyle> | ((state: PressableStateCallbackType) => StyleProp<ViewStyle>);
210
unstable_pressDelay?: number;
211
simultaneousWithExternalGesture?: GestureRef[];
212
requireExternalGestureToFail?: GestureRef[];
213
blocksExternalGesture?: GestureRef[];
214
}
215
216
interface PressableStateCallbackType {
217
pressed: boolean;
218
hovered?: boolean;
219
focused?: boolean;
220
}
221
222
interface AndroidRippleConfig {
223
color?: string;
224
borderless?: boolean;
225
radius?: number;
226
foreground?: boolean;
227
}
228
```
229
230
**Usage Example:**
231
232
```typescript
233
import React from "react";
234
import { Text, View } from "react-native";
235
import { Pressable } from "react-native-gesture-handler";
236
237
function MyPressable() {
238
return (
239
<Pressable
240
onPress={() => console.log("Pressable pressed")}
241
onLongPress={() => console.log("Pressable long pressed")}
242
android_ripple={{ color: "rgba(0,0,0,0.1)", borderless: false }}
243
style={({ pressed }) => [
244
{
245
padding: 15,
246
backgroundColor: pressed ? "#e0e0e0" : "white",
247
borderRadius: 8,
248
borderWidth: 1,
249
borderColor: "#ccc",
250
},
251
]}
252
>
253
{({ pressed }) => (
254
<Text style={{ color: pressed ? "blue" : "black" }}>
255
{pressed ? "Pressed!" : "Press me"}
256
</Text>
257
)}
258
</Pressable>
259
);
260
}
261
```
262
263
### DrawerLayout (Deprecated)
264
265
Drawer layout component for creating side navigation panels. This component is deprecated in favor of the react-native-reanimated version.
266
267
```typescript { .api }
268
/**
269
* Drawer layout component (deprecated)
270
* Use react-native-reanimated drawer implementations instead
271
* @deprecated Use DrawerLayout from react-native-reanimated
272
*/
273
function DrawerLayout(props: {
274
drawerPosition: DrawerPosition;
275
drawerWidth?: number;
276
drawerBackgroundColor?: string;
277
drawerLockMode?: DrawerLockMode;
278
keyboardDismissMode?: DrawerKeyboardDismissMode;
279
onDrawerClose?: () => void;
280
onDrawerOpen?: () => void;
281
onDrawerSlide?: (event: DrawerSlideEvent) => void;
282
onDrawerStateChanged?: (newState: DrawerState) => void;
283
renderNavigationView: () => React.ReactNode;
284
statusBarBackgroundColor?: string;
285
drawerType?: DrawerType;
286
overlayColor?: string;
287
contentContainerStyle?: StyleProp<ViewStyle>;
288
edgeWidth?: number;
289
minSwipeDistance?: number;
290
hideStatusBar?: boolean;
291
statusBarAnimation?: "slide" | "fade" | "none";
292
children?: React.ReactNode;
293
}): JSX.Element;
294
295
interface DrawerLayoutProps {
296
drawerPosition: DrawerPosition;
297
drawerWidth?: number;
298
drawerBackgroundColor?: string;
299
drawerLockMode?: DrawerLockMode;
300
keyboardDismissMode?: DrawerKeyboardDismissMode;
301
onDrawerClose?: () => void;
302
onDrawerOpen?: () => void;
303
onDrawerSlide?: (event: DrawerSlideEvent) => void;
304
onDrawerStateChanged?: (newState: DrawerState) => void;
305
renderNavigationView: () => React.ReactNode;
306
statusBarBackgroundColor?: string;
307
drawerType?: DrawerType;
308
overlayColor?: string;
309
contentContainerStyle?: StyleProp<ViewStyle>;
310
edgeWidth?: number;
311
minSwipeDistance?: number;
312
hideStatusBar?: boolean;
313
statusBarAnimation?: "slide" | "fade" | "none";
314
children?: React.ReactNode;
315
}
316
317
// Drawer-related types
318
type DrawerPosition = "left" | "right";
319
type DrawerState = "Idle" | "Dragging" | "Settling";
320
type DrawerType = "front" | "back" | "slide";
321
type DrawerLockMode = "unlocked" | "locked-closed" | "locked-open";
322
type DrawerKeyboardDismissMode = "none" | "on-drag";
323
324
interface DrawerSlideEvent {
325
nativeEvent: {
326
offset: number;
327
};
328
}
329
```
330
331
## Utility Components
332
333
### createNativeWrapper
334
335
Function for wrapping React Native components to add gesture handler capabilities.
336
337
```typescript { .api }
338
/**
339
* Creates a native wrapper for React Native components
340
* Adds gesture handling capabilities to existing components
341
*/
342
function createNativeWrapper<T>(
343
Component: React.ComponentType<T>,
344
config?: {
345
shouldCancelWhenOutside?: boolean;
346
shouldActivateOnStart?: boolean;
347
disallowInterruption?: boolean;
348
}
349
): React.ComponentType<T & {
350
waitFor?: React.Ref<any> | React.Ref<any>[];
351
simultaneousHandlers?: React.Ref<any> | React.Ref<any>[];
352
}>;
353
```
354
355
**Usage Example:**
356
357
```typescript
358
import React from "react";
359
import { View } from "react-native";
360
import { createNativeWrapper } from "react-native-gesture-handler";
361
362
const WrappedView = createNativeWrapper(View, {
363
shouldCancelWhenOutside: true,
364
shouldActivateOnStart: true,
365
});
366
367
function MyWrappedView() {
368
return (
369
<WrappedView
370
style={{ width: 100, height: 100, backgroundColor: "red" }}
371
onGestureEvent={(event) => {
372
console.log("Gesture event:", event.nativeEvent);
373
}}
374
/>
375
);
376
}
377
```
378
379
## Advanced Animation Integration
380
381
### Reanimated Integration
382
383
Advanced components work seamlessly with react-native-reanimated for smooth animations:
384
385
```typescript
386
import React from "react";
387
import { View } from "react-native";
388
import Animated, {
389
useSharedValue,
390
useAnimatedStyle,
391
withSpring
392
} from "react-native-reanimated";
393
import { Pressable } from "react-native-gesture-handler";
394
395
function AnimatedPressable() {
396
const scale = useSharedValue(1);
397
398
const animatedStyle = useAnimatedStyle(() => ({
399
transform: [{ scale: scale.value }],
400
}));
401
402
return (
403
<Pressable
404
onPressIn={() => {
405
scale.value = withSpring(0.95);
406
}}
407
onPressOut={() => {
408
scale.value = withSpring(1);
409
}}
410
>
411
<Animated.View style={[{ padding: 20, backgroundColor: "blue" }, animatedStyle]}>
412
{/* Content */}
413
</Animated.View>
414
</Pressable>
415
);
416
}
417
```
418
419
### Swipeable Animation Customization
420
421
Customize Swipeable animations with detailed control:
422
423
```typescript
424
import React from "react";
425
import { View, Text, Animated } from "react-native";
426
import { Swipeable } from "react-native-gesture-handler";
427
428
function CustomAnimatedSwipeable() {
429
const renderRightActions = (progress, dragX) => {
430
// Custom scaling animation
431
const scale = progress.interpolate({
432
inputRange: [0, 1],
433
outputRange: [0.8, 1],
434
});
435
436
// Custom opacity animation
437
const opacity = progress.interpolate({
438
inputRange: [0, 0.5, 1],
439
outputRange: [0, 0.5, 1],
440
});
441
442
return (
443
<Animated.View
444
style={{
445
flex: 1,
446
backgroundColor: "red",
447
justifyContent: "center",
448
alignItems: "center",
449
transform: [{ scale }],
450
opacity,
451
}}
452
>
453
<Text style={{ color: "white", fontWeight: "bold" }}>Delete</Text>
454
</Animated.View>
455
);
456
};
457
458
return (
459
<Swipeable
460
renderRightActions={renderRightActions}
461
friction={1.5}
462
rightThreshold={40}
463
>
464
<View style={{ padding: 20, backgroundColor: "white" }}>
465
<Text>Swipe left for custom animation</Text>
466
</View>
467
</Swipeable>
468
);
469
}
470
```
471
472
## Performance Considerations
473
474
### Memory Management
475
476
Advanced components are optimized for memory efficiency:
477
478
- Automatic cleanup of gesture recognizers
479
- Efficient animation value management
480
- Reduced memory allocation during gestures
481
482
### Native Performance
483
484
Components leverage native implementations for optimal performance:
485
486
- Native thread gesture recognition
487
- Hardware-accelerated animations
488
- Minimal JavaScript bridge usage during interactions
489
490
### Best Practices
491
492
```typescript
493
// ✅ Good: Use refs for programmatic control
494
const swipeableRef = useRef<Swipeable>(null);
495
496
// ✅ Good: Cleanup in useEffect
497
useEffect(() => {
498
return () => {
499
swipeableRef.current?.close();
500
};
501
}, []);
502
503
// ❌ Avoid: Creating new objects in render
504
const renderActions = () => ({ flex: 1 }); // Creates new object each render
505
506
// ✅ Better: Use static styles or useMemo
507
const actionStyles = { flex: 1 };
508
const renderActions = () => actionStyles;
509
```