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, където ефектът на натискане е твърдо определен (промяна на прозрачността), Pressable предоставя функция, която получава текущото състояние. Разработчикът сам решава как да реагира визуално на допир: да промени цвета, мащаба, сянката или комбинация от ефекти. Това предоставя пълен контрол над UX.
Pressable определя три състояния на взаимодействие: pressed (пръст на екрана), hovered (курсор над елемента на Web/TV), focused (елемент във фокус на клавиатурата). Всяко състояние активира съответното обратно извикване и се предава на функцията за стилове и на функцията за рендиране на деца.
| Състояние | Условие | Типична реакция |
|---|---|---|
| pressed | Пръст на екрана или клик натиснат | Промяна на прозрачността, мащаба, цвета на фона |
| hovered | Курсор над елемента (Web, TV) | Осветляване, сянка, подчертаване |
| focused | Елемент във фокус на клавиатурата | Контур, рамка, промяна на цвета |
Важно: 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 позволява създаване на персонализирани анимации.
Допълнителни props: 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 — prop на Pressable, който разширява областта на допир извън видимите граници на компонента. Критичен е за малки елементи: икони, квадратчета за избор, радио бутони. Apple HIG препоръчва минимален размер на touch target от 44x44 точки. hitSlop позволява изпълняването на това изискване без промяна на визуалния размер.
hitSlop приема обект { top, bottom, left, right } или едно число за всички страни. Стойностите се посочват в логически пиксели (dp/pt). За икони 24x24 се препоръчва hitSlop от поне 10-12 от всяка страна за постигане на touch target от 44x44.
<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 + прозрачност в 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 и прозрачност, нативният драйвер се поддържа на всички платформи.
Често задавани въпроси
Не, Pressable има различно API. TouchableOpacity автоматично прилага прозрачност при натискане. Pressable изисква явно посочване на стила чрез функцията за състояние. Замяната е тривиална: предайте style={({ pressed }) => [{ opacity: pressed ? 0.5 : 1 }]}.
Използвайте prop android_ripple с обект { color, borderless }. Цветът на ripple се посочва в rgba формат. За кръгли бутони използвайте borderless: true. Ripple работи само на Android 5+. На iOS използвайте персонализирана анимация.
Pressable има вградена защита срещу случайни натискания при превъртане. Ако потребителят превърта списък, onPress не се вика. Този поведение може да се настрои чрез pressRetentionOffset и delayPressIn.
Използвайте prop onLongPress — вградена подкрепа за дълго натискане. Забавянето се настройва чрез delayLongPress (по подразбиране 500 ms). За контекстни менюта и drag-and-drop, комбинирайте onLongPress с onPressIn.
Да, Pressable подкрепя focused състояние за навигация с клавиатура на Android TV, Apple TV и Web. Използвайте стилизация чрез { focused } за показване на фокус. На мобилни устройства focused състоянието не е приложимо.
Заключение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също