User Interaction in React Native: Events and Gestures
The Story of Your App’s Conversation
Imagine your app is like a friendly robot that wants to understand what you’re doing. When you tap, swipe, or type, you’re talking to it. The robot needs special ears (called event handlers) to listen and respond to you!
What is Event Handling?
Think of event handling like a doorbell. When someone presses the bell (the event), the sound plays (the response). Your app works the same way!
Simple Example: The Button Tap
<Button
title="Say Hello"
onPress={() => console.log('Hello!')}
/>
When you tap the button, it says “Hello!” Simple, right?
The Event Object
Every time something happens, your app gets a little note with details about what happened. This note is called an event object.
onPress={(event) => {
console.log('You tapped at:',
event.nativeEvent.locationX);
}}
The note tells you where you tapped, when it happened, and more!
Touch Events: The Five Ways to Touch
Your phone understands five different ways you can touch it. Think of them like five different handshakes!
graph TD A["Touch Events"] --> B["TouchableOpacity"] A --> C["TouchableHighlight"] A --> D["TouchableWithoutFeedback"] A --> E["Pressable"] A --> F["TouchableNativeFeedback"] B --> B1["Fades when pressed"] C --> C1["Lights up when pressed"] D --> D1["No visual change"] E --> E1["Modern & flexible"] F --> F1["Android ripple"]
TouchableOpacity: The Fading Button
When you press it, it becomes a little see-through. Like a ghost!
<TouchableOpacity
onPress={() => alert('Tapped!')}
activeOpacity={0.5}
>
<Text>Press Me</Text>
</TouchableOpacity>
TouchableHighlight: The Glowing Button
When you press it, a color appears underneath. Like magic!
<TouchableHighlight
onPress={() => alert('Pressed!')}
underlayColor="#DDDDDD"
>
<Text>Press Me</Text>
</TouchableHighlight>
TouchableWithoutFeedback: The Invisible Listener
It listens but doesn’t show any change. Perfect for hiding secret taps!
<TouchableWithoutFeedback
onPress={() => console.log('Secret tap!')}
>
<View style={styles.box} />
</TouchableWithoutFeedback>
Pressable: The Modern Hero
The newest and most powerful! It can do everything.
<Pressable
onPress={() => console.log('Pressed!')}
onPressIn={() => console.log('Finger down')}
onPressOut={() => console.log('Finger up')}
onLongPress={() => console.log('Long press!')}
>
<Text>Super Button</Text>
</Pressable>
TouchableNativeFeedback: The Android Special
Only for Android! Shows a beautiful ripple effect.
<TouchableNativeFeedback
onPress={() => console.log('Ripple!')}
background={TouchableNativeFeedback
.Ripple('#000', false)}
>
<View style={styles.button}>
<Text>Android Button</Text>
</View>
</TouchableNativeFeedback>
Gesture Responder System: Who’s in Charge?
Imagine many kids all want to play with the same toy. The Gesture Responder System decides who gets to play!
The Four Big Questions
When you touch the screen, your app asks:
graph TD A["Touch Starts"] --> B{Can I be the responder?} B -->|Yes| C["onStartShouldSetResponder"] B -->|Moving?| D["onMoveShouldSetResponder"] C --> E[I'm in control!] D --> E E --> F["onResponderGrant"] E --> G["onResponderMove"] E --> H["onResponderRelease"]
The Simple Version
<View
onStartShouldSetResponder={() => true}
onResponderGrant={() =>
console.log('I got control!')}
onResponderMove={() =>
console.log('Moving...')}
onResponderRelease={() =>
console.log('Touch ended!')}
>
<Text>Touch me!</Text>
</View>
Why This Matters
If you have a scrolling list inside a swipeable card, who should move? The list or the card? The Gesture Responder System figures this out!
PanResponder: The Movement Master
PanResponder is like teaching your robot to follow your finger. It’s perfect for dragging things around!
Think of It Like a Puppet
Your finger is the puppet master. The element on screen is the puppet. PanResponder is the strings connecting them!
Building a Draggable Box
const pan = useRef(
new Animated.ValueXY()
).current;
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder:
() => true,
onPanResponderMove:
Animated.event(
[null, {dx: pan.x, dy: pan.y}],
{useNativeDriver: false}
),
onPanResponderRelease: () => {
Animated.spring(pan, {
toValue: {x: 0, y: 0},
useNativeDriver: false
}).start();
}
})
).current;
Using the Draggable Box
<Animated.View
style={{
transform: [
{translateX: pan.x},
{translateY: pan.y}
]
}}
{...panResponder.panHandlers}
>
<Text>Drag Me!</Text>
</Animated.View>
PanResponder Events Explained
| Event | What It Means |
|---|---|
dx |
How far moved left/right |
dy |
How far moved up/down |
vx |
Speed going left/right |
vy |
Speed going up/down |
x0 |
Where touch started (X) |
y0 |
Where touch started (Y) |
Keyboard Events: When You Type
When the keyboard pops up, your app needs to know! Otherwise, the keyboard might cover important stuff.
The Problem
Imagine you’re filling out a form. You tap the last field, the keyboard appears… and now you can’t see what you’re typing!
The Solution: KeyboardAvoidingView
<KeyboardAvoidingView
behavior={Platform.OS === 'ios'
? 'padding'
: 'height'}
style={{flex: 1}}
>
<TextInput
placeholder="Type here..."
style={styles.input}
/>
<Button title="Submit" />
</KeyboardAvoidingView>
Keyboard Show and Hide Events
Your app can listen for when the keyboard appears or disappears.
useEffect(() => {
const showListener =
Keyboard.addListener(
'keyboardDidShow',
() => console.log('Keyboard up!')
);
const hideListener =
Keyboard.addListener(
'keyboardDidHide',
() => console.log('Keyboard gone!')
);
return () => {
showListener.remove();
hideListener.remove();
};
}, []);
Keyboard API: Your Keyboard Remote Control
The Keyboard API is like a TV remote for your keyboard. You can make it appear, disappear, and more!
Dismiss the Keyboard
When you tap outside a text field, hide the keyboard:
<TouchableWithoutFeedback
onPress={Keyboard.dismiss}
>
<View style={styles.container}>
<TextInput placeholder="Tap outside" />
</View>
</TouchableWithoutFeedback>
All Keyboard Events
graph TD A["Keyboard API"] --> B["keyboardWillShow"] A --> C["keyboardDidShow"] A --> D["keyboardWillHide"] A --> E["keyboardDidHide"] A --> F["keyboardWillChangeFrame"] A --> G["keyboardDidChangeFrame"] B --> B1["iOS only - Before show"] C --> C1["After fully shown"] D --> D1["iOS only - Before hide"] E --> E1["After fully hidden"]
Getting Keyboard Height
Sometimes you need to know how tall the keyboard is:
Keyboard.addListener(
'keyboardDidShow',
(e) => {
const height =
e.endCoordinates.height;
console.log('Keyboard is',
height, 'pixels tall');
}
);
Quick Reference: When to Use What?
| I Want To… | Use This! |
|---|---|
| Simple button tap | onPress |
| Button with fade effect | TouchableOpacity |
| Drag something | PanResponder |
| Handle complex touches | Gesture Responder |
| Hide keyboard on tap outside | Keyboard.dismiss |
| Move content when keyboard shows | KeyboardAvoidingView |
The Big Picture
graph TD A["User Touches Screen"] --> B{What type?} B --> C["Single Tap"] B --> D["Drag/Swipe"] B --> E["Type on Keyboard"] C --> C1["Touch Events"] C1 --> C2["Pressable/Touchable"] D --> D1["Gesture System"] D1 --> D2["PanResponder"] E --> E1["Keyboard API"] E1 --> E2["KeyboardAvoidingView"]
You Did It!
You now understand how your app listens to users! Remember:
- Touch Events = Simple taps and presses
- Gesture Responder = Who handles the touch
- PanResponder = Dragging and complex gestures
- Keyboard Events = When typing starts/stops
- Keyboard API = Control the keyboard
Your app is no longer just a screen. It’s a conversation partner that listens and responds to every touch, swipe, and keystroke!
