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) | Подсветка, тень, underline |
| focused | Элемент в фокусе клавиатуры | Outline, 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>Pressable API включает четыре основных колбэка: onPress (полное нажатие с отпусканием), onLongPress (долгое нажатие), onPressIn (начало касания) и onPressOut (окончание касания). Комбинация onPressIn и onPressOut позволяет создавать кастомные анимации.
Дополнительные пропсы: delayLongPress (задержка длинного нажатия, по умолчанию 500 ms), pressRetentionOffset (область, за пределами которой нажатие отменяется), android_ripple (эффект ripple на Android). Важно: Ripple работает только на Android 5+.
<Pressable
onPress={() => console.log('Pressed')}
onLongPress={() => console.log('Long press')}
onPressIn={() => console.log('Finger down')}
onPressOut={() => console.log('Finger up')}
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 44x44 точки. hitSlop позволяет соблюсти это требование без изменения визуального размера.
hitSlop принимает объект { top, bottom, left, right } или единое число для всех сторон. Значения задаются в логических пикселях (dp/pt). Для иконок 24x24 рекомендуется hitSlop минимум 10-12 с каждой стороны, чтобы достичь 44x44 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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также