Pressable — nowoczesny komponent React Native do obsługi dotknięć, zastępujący przestarzałe TouchableHighlight, TouchableOpacity i TouchableWithoutFeedback. Pressable udostępnia jednolity API z wykrywaniem stanów pressed, hovered i focused. Komponent pojawił się w React Native 0.63 i jest zalecany przez Meta dla wszystkich nowych projektów. Więcej o komponencie przeczytasz w dokumentacji Meta.
Najważniejsze
Pressable — komponent React Native udostępniający jednolity interfejs do obsługi wszystkich typów dotknięć. W przeciwieństwie do trzech różnych komponentów Touchable (TouchableHighlight, TouchableOpacity, TouchableWithoutFeedback), Pressable zastępuje je jednym z elastycznym systemem stanów i stylizacji.
Komponent został wprowadzony w React Native 0.63 (wrzesień 2020). Według danych Meta (2026), 70% nowych projektów na React Native używa Pressable zamiast komponentów Touchable. Pressable rozwiązuje kluczowy problem Touchable — rozproszone API i konieczność przełączania się między komponentami dla różnych efektów.
W przeciwieństwie do TouchableOpacity, gdzie efekt dotknięcia jest sztywno określony (zmiana przezroczystości), Pressable udostępnia funkcję odbierającą bieżący stan. Deweloper sam decyduje, jak wizualnie reagować na dotknięcie: zmienić kolor, skalę, cień lub kombinację efektów. Daje to pełną kontrolę nad UX.
Pressable definiuje trzy stany interakcji: pressed (palec na ekranie), hovered (kursor nad elementem na Web/TV), focused (element w fokusie klawiatury). Każdy stan aktywuje odpowiedni callback i jest przekazywany do funkcji stylów oraz funkcji renderującej dzieci.
| Stan | Warunek | Typowa reakcja |
|---|---|---|
| pressed | Palec na ekranie lub kliknięcie przytrzymane | Zmiana przezroczystości, skali, koloru tła |
| hovered | Kursor nad elementem (Web, TV) | Podświetlenie, cień, podkreślenie |
| focused | Element w fokusie klawiatury | Konturka, obramowanie, zmiana koloru |
Ważne: hovered i focused działają tylko na platformach z obsługą wskaźnika (Web, Android TV, Apple TV). Na urządzeniach mobilnych dostępny jest tylko stan pressed. W przypadku aplikacji wieloplatformowych projektuj reakcje wizualne, mając to ograniczenie na uwadze.
<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 zawiera cztery główne callbacki: onPress (pełne naciśnięcie z puszczeniem), onLongPress (długie naciśnięcie), onPressIn (początek dotknięcia) i onPressOut (koniec dotknięcia). Kombinacja onPressIn i onPressOut pozwala tworzyć niestandardowe animacje.
Dodatkowe props: delayLongPress (opóźnienie długiego naciśnięcia, domyślnie 500 ms), pressRetentionOffset (obszar, poza którym naciśnięcie jest anulowane), android_ripple (efekt ripple na Androidzie). Ważne: Ripple działa tylko na Android 5+.
<Pressable
onPress={() => console.log('Naciśnięto')}
onLongPress={() => console.log('Długie naciśnięcie')}
onPressIn={() => console.log('Palec w dół')}
onPressOut={() => console.log('Palec w górę')}
delayLongPress={300}
android_ripple={{ color: 'rgba(0,0,0,0.1)', borderless: false }}
style={styles.button}>
<Text>Press me</Text>
</Pressable>onPress jest wywoływany tylko wtedy, gdy palec zostanie podniesiony wewnątrz obszaru komponentu (z uwzględnieniem pressRetentionOffset). Jeśli użytkownik przesunie palec poza granice, onPress nie zadziała, co zapobiega fałszywym naciśnięciom. onPressOut jest wywoływany w każdym przypadku przy puszczeniu.
hitSlop — props Pressable rozszerzający obszar dotyku poza widoczne granice komponentu. Jest to krytyczne dla małych elementów: ikon, checkboxów, przycisków radio. Apple HIG zaleca minimalny rozmiar touch target 44x44 punkty. hitSlop pozwala spełnić to wymaganie bez zmiany rozmiaru wizualnego.
hitSlop przyjmuje obiekt { top, bottom, left, right } lub pojedynczą liczbę dla wszystkich stron. Wartości podawane są w logicznych pikselach (dp/pt). Dla ikon 24x24 zalecany hitSlop to minimum 10-12 z każdej strony, aby osiągnąć 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 — odwrotność hitSlop: określa obszar, na który użytkownik może wyjść poza granice komponentu bez anulowania naciśnięcia. Domyślnie jest równy hitSlop. Jeśli potrzebujesz, aby naciśnięcie było zachowane przy wyjściu poza granice, zwiększ pressRetentionOffset.
Pressable vs Touchable — kluczowe pytanie przy wyborze komponentu do obsługi dotknięć. TouchableOpacity, TouchableHighlight i TouchableWithoutFeedback to przestarzałe komponenty, które nie zostaną usunięte, ale nie otrzymują nowych funkcji. Meta zaleca Pressable dla nowych projektów.
Główne zalety Pressable: jednolity API dla wszystkich typów efektów, dostęp do stanu pressed dla niestandardowej stylizacji, obsługa stanów hovered/focused, hitSlop i pressRetentionOffset, callback onLongPress bez dodatkowej konfiguracji. TouchableOpacity nadaje się tylko do prostej zmiany przezroczystości.
| Scenariusz | Touchable | Pressable |
|---|---|---|
| Proste naciśnięcie | TouchableOpacity | Pressable + przezroczystość w style |
| Podświetlenie tła | TouchableHighlight | Pressable + backgroundColor |
| Bez efektu wizualnego | TouchableWithoutFeedback | Pressable z pustym style |
| Długie naciśnięcie | onLongPress na dowolnym Touchable | onLongPress na Pressable |
| Niestandardowa animacja | Animated + onPressIn/Out | Pressable + useAnimatedStyle |
| Ripple na Androidzie | TouchableNativeFeedback | Pressable + android_ripple |
Pressable pozwala tworzyć złożone elementy interaktywne z minimalną ilością kodu. Poniżej — przykład animowanego przycisku ze zmianą skali przy naciśnięciu i efektem ripple na Androidzie. Taki przycisk zastępuje kombinację 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>
);
};Ważne: używaj useNativeDriver: true dla animacji w Pressable. Przenosi to animację do natywnego wątku, zapobiegając spadkom klatek przy szybkich naciśnięciach. Dla transform i przezroczystości natywny sterownik jest obsługiwany na wszystkich platformach.
Często zadawane pytania
Nie, Pressable ma inne API. TouchableOpacity automatycznie stosuje przezroczystość przy naciśnięciu. Pressable wymaga jawnego określenia stylu przez funkcję stanu. Zastąpienie jest trywialne: przekaż style={({ pressed }) => [{ opacity: pressed ? 0.5 : 1 }]}.
Użyj propsa android_ripple z obiektem { color, borderless }. Kolor ripple podaje się w formacie rgba. Dla okrągłych przycisków użyj borderless: true. Ripple działa tylko na Android 5+. Na iOS używaj niestandardowej animacji.
Pressable ma wbudowaną ochronę przed przypadkowymi naciśnięciami podczas przewijania. Jeśli użytkownik przewija listę, onPress nie jest wywoływane. To zachowanie można skonfigurować przez pressRetentionOffset i delayPressIn.
Użyj propsa onLongPress — wbudowana obsługa długiego naciśnięcia. Opóźnienie konfiguruje się przez delayLongPress (domyślnie 500 ms). Dla menu kontekstowych i drag-and-drop połącz onLongPress z onPressIn.
Tak, Pressable obsługuje stan focused do nawigacji klawiaturowej na Android TV, Apple TV i Web. Użyj stylizacji przez { focused } do wyświetlania fokusu. Na urządzeniach mobilnych stan focused nie ma zastosowania.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również