Pressable — сучасний компонент React Native для обробки дотиків, який замінює застарілі TouchableHighlight, TouchableOpacity та TouchableWithoutFeedback. Pressable надає єдиний API з виявленням станів pressed, hovered та focused. Компонент з’явився в React Native 0.63 і рекомендується Meta для всіх нових проєктів. Докладніше про компонент читайте в документації Meta.
Головне
Pressable — компонент React Native, що надає єдиний інтерфейс для обробки всіх типів дотиків. На відміну від трьох різних Touchable-компонентів (TouchableHighlight, TouchableOpacity, TouchableWithoutFeedback), Pressable замінює їх одним із гнучкою системою станів та стилізації.
Компонент було представлено в React Native 0.63 (вересень 2020). За даними Meta (2026), 70% нових проєктів на React Native використовують Pressable замість Touchable-компонентів. Pressable вирішує ключову проблему Touchable — розрізнений API та необхідність перемикатися між компонентами для різних ефектів.
На відміну від TouchableOpacity, де ефект натискання жорстко заданий (зміна opacity), Pressable надає функцію, яка отримує поточний стан. Розробник сам вирішує, як візуально реагувати на натискання: змінити колір, масштаб, тінь або комбінацію ефектів. Це дає повний контроль над UX.
Pressable визначає три стани взаємодії: pressed (палець на екрані), hovered (курсор над елементом на Web/TV), focused (елемент у фокусі клавіатури). Кожен стан активує відповідний колбек і передається в функцію стилів та дочірню render-функцію.
| Стан | Умова | Типова реакція |
|---|---|---|
| pressed | Палець на екрані або клік затиснутий | Зміна opacity, scale, кольору фону |
| hovered | Курсор над елементом (Web, TV) | Підсвітка, тінь, підкреслення |
| focused | Елемент у фокусі клавіатури | Обведення, border, зміна кольору |
Важливо: hovered та focused працюють лише на платформах із підтримкою вказівника (Web, Android TV, Apple TV). На мобільних пристроях доступний лише pressed. Для крос-платформових застосунків проєктуйте візуальні реакції з огляду на це обмеження.
<Pressable
style={({ pressed }) => [
styles.button,
pressed && styles.buttonPressed,
]}
onPress={handlePress}>
{({ pressed }) => (
<Text style={pressed ? styles.textPressed : styles.text}>
{pressed ? 'Release' : 'Press'}
</Text>
)}
</Pressable>API Pressable включає чотири основні колбеки: onPress (повне натискання з відпусканням), onLongPress (довге натискання), onPressIn (початок дотику) та onPressOut (закінчення дотику). Комбінація onPressIn та onPressOut дозволяє створювати кастомні анімації.
Додаткові пропси: delayLongPress (затримка довгого натискання, за замовчуванням 500 ms), pressRetentionOffset (область, за межами якої натискання скасовується), android_ripple (ефект ripple на Android). Важливо: Ripple працює лише на Android 5+.
<Pressable
onPress={() => console.log('Натиснуто')}
onLongPress={() => console.log('Довге натискання')}
onPressIn={() => console.log('Палець вниз')}
onPressOut={() => console.log('Палець вгору')}
delayLongPress={300}
android_ripple={{ color: 'rgba(0,0,0,0.1)', borderless: false }}
style={styles.button}>
<Text>Press me</Text>
</Pressable>onPress викликається лише якщо палець піднято всередині області компонента (з урахуванням pressRetentionOffset). Якщо користувач відводить палець за межі, onPress не спрацьовує, що запобігає хибним натисканням. onPressOut викликається в будь-якому разі при відпусканні.
hitSlop — пропс Pressable, що розширює область дотику за межі видимих меж компонента. Це критично для маленьких елементів: іконок, чекбоксів, радіо-кнопок. Apple HIG рекомендує мінімальний розмір touch target 44×44 точки. hitSlop дозволяє дотриматися цієї вимоги без зміни візуального розміру.
hitSlop приймає об’єкт { top, bottom, left, right } або єдине число для всіх сторін. Значення задаються в логічних пікселях (dp/pt). Для іконок 24×44 рекомендується hitSlop мінімум 10–12 з кожного боку, щоб досягти 44×44 touch target.
<Pressable
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
onPress={handleIconPress}
style={styles.iconButton}>
<Icon name="star" size={24} />
</Pressable>pressRetentionOffset — зворотній hitSlop: визначає область, на яку користувач може вийти за межі компонента, не скасовуючи натискання. За замовчуванням дорівнює hitSlop. Якщо потрібно, щоб натискання зберігалося при виході за межі, збільште pressRetentionOffset.
Pressable vs Touchable — ключове питання при виборі компонента для обробки дотиків. TouchableOpacity, TouchableHighlight та TouchableWithoutFeedback — застарілі компоненти, які не будуть видалені, але не отримують нових можливостей. Meta рекомендує Pressable для нових проєктів.
Основні переваги Pressable: єдиний API для всіх типів ефектів, доступ до стану pressed для кастомної стилізації, підтримка станів hovered/focused, hitSlop та pressRetentionOffset, колбек onLongPress без додаткових налаштувань. TouchableOpacity підходить лише для простої зміни прозорості.
| Сценарій | Touchable | Pressable |
|---|---|---|
| Просте натискання | TouchableOpacity | Pressable + opacity в style |
| Підсвітка фону | TouchableHighlight | Pressable + backgroundColor |
| Без візуального ефекту | TouchableWithoutFeedback | Pressable із порожнім style |
| Довге натискання | onLongPress на будь-якому Touchable | onLongPress на Pressable |
| Кастомна анімація | Animated + onPressIn/Out | Pressable + useAnimatedStyle |
| Ripple на Android | TouchableNativeFeedback | Pressable + android_ripple |
Pressable дозволяє створювати складні інтерактивні елементи з мінімальним кодом. Нижче — приклад анімованої кнопки зі зміною масштабу при натисканні та ripple-ефектом на Android. Така кнопка замінює комбінацію TouchableOpacity + Animated.
const AnimatedButton = ({ title, onPress }) => {
const scale = React.useRef(new Animated.Value(1)).current;
const handlePressIn = () => {
Animated.spring(scale, {
toValue: 0.96,
useNativeDriver: true,
}).start();
};
const handlePressOut = () => {
Animated.spring(scale, {
toValue: 1,
friction: 3,
useNativeDriver: true,
}).start();
};
return (
<Pressable
onPress={onPress}
onPressIn={handlePressIn}
onPressOut={handlePressOut}
android_ripple={{ color: 'rgba(255,255,255,0.3)' }}
style={styles.button}>
<AnimatedView style={[styles.inner, { transform: [{ scale }] }]}>
<Text style={styles.text}>{title}</Text>
</AnimatedView>
</Pressable>
);
};Важливо: використовуйте useNativeDriver: true для анімацій у Pressable. Це переносить анімацію в нативний потік, запобігаючи просіданню кадрів при швидких натисканнях. Для transform та opacity нативний драйвер підтримується на всіх платформах.
Часті запитання
Ні, Pressable має інший API. TouchableOpacity автоматично застосовує opacity при натисканні. Pressable вимагає явного вказання стилю через функцію стану. Заміна тривіальна: передайте style={({ pressed }) => [{ opacity: pressed ? 0.5 : 1 }]}.
Використовуйте пропс android_ripple з об’єктом { color, borderless }. Колір ripple задається у форматі rgba. Для круглих кнопок використовуйте borderless: true. Ripple працює лише на Android 5+. На iOS використовуйте кастомну анімацію.
Pressable має вбудований захист від випадкових натискань при скролі. Якщо користувач скролить список, onPress не викликається. Цю поведінку можна налаштувати через pressRetentionOffset та delayPressIn.
Використовуйте пропс onLongPress — вбудована підтримка довгого натискання. Затримка налаштовується через delayLongPress (за замовчуванням 500 ms). Для контекстних меню та drag-and-drop комбінуйте onLongPress з onPressIn.
Так, Pressable підтримує стан focused для клавіатурної навігації на Android TV, Apple TV та Web. Використовуйте стилізацію через { focused } для відображення фокусу. На мобільних пристроях стан focused не актуальний.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також