Pressable là một thành phần React Native hiện đại để xử lý cảm ứng, thay thế các TouchableHighlight, TouchableOpacity và TouchableWithoutFeedback cũ. Pressable cung cấp API thống nhất với khả năng phát hiện các trạng thái pressed, hovered và focused. Thành phần này được giới thiệu trong React Native 0.63 và được Meta khuyên dùng cho tất cả các dự án mới. Tìm hiểu thêm trong tài liệu của Meta.
Các điểm chính
Pressable là một thành phần React Native cung cấp giao diện thống nhất để xử lý tất cả các loại cảm ứng. Không giống như ba thành phần Touchable khác nhau (TouchableHighlight, TouchableOpacity, TouchableWithoutFeedback), Pressable thay thế tất cả chúng bằng một hệ thống trạng thái và kiểu dáng linh hoạt.
Thành phần này được giới thiệu trong React Native 0.63 (tháng 9 năm 2020). Theo Meta (2026), 70% các dự án React Native mới sử dụng Pressable thay vì các thành phần Touchable. Pressable giải quyết vấn đề chính của Touchable — API phân mảnh và nhu cầu chuyển đổi giữa các thành phần cho các hiệu ứng khác nhau.
Không giống như TouchableOpacity, nơi hiệu ứng nhấn được cố định (thay đổi độ mờ), Pressable cung cấp một hàm nhận trạng thái hiện tại. Nhà phát triển quyết định cách phản ứng trực quan với một lần nhấn: thay đổi màu sắc, tỷ lệ, bóng hoặc kết hợp các hiệu ứng. Điều này mang lại toàn quyền kiểm soát UX.
Pressable xác định ba trạng thái tương tác: pressed (ngón tay trên màn hình), hovered (con trỏ trên phần tử trên Web/TV), focused (phần tử đang được tiêu điểm bàn phím). Mỗi trạng thái kích hoạt callback tương ứng và được truyền vào hàm tạo kiểu và hàm kết xuất con.
| Trạng thái | Điều kiện | Phản ứng điển hình |
|---|---|---|
| pressed | Ngón tay trên màn hình hoặc nhấn giữ | Thay đổi độ mờ, tỷ lệ hoặc màu nền |
| hovered | Con trỏ trên phần tử (Web, TV) | Làm nổi bật, bóng, gạch chân |
| focused | Phần tử đang được tiêu điểm bàn phím | Đường viền, khung, thay đổi màu |
Quan trọng: hovered và focused chỉ hoạt động trên các nền tảng hỗ trợ con trỏ (Web, Android TV, Apple TV). Trên thiết bị di động, chỉ pressed khả dụng. Đối với các ứng dụng đa nền tảng, hãy thiết kế phản ứng trực quan cân nhắc giới hạn này.
<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 bao gồm bốn callback chính: onPress (nhấn đầy đủ với thả ra), onLongPress (nhấn giữ), onPressIn (bắt đầu chạm) và onPressOut (kết thúc chạm). Sự kết hợp của onPressIn và onPressOut cho phép tạo hoạt ảnh tùy chỉnh.
Các props bổ sung: delayLongPress (độ trễ nhấn giữ, mặc định 500 ms), pressRetentionOffset (vùng mà ngoài đó nhấn bị hủy), android_ripple (hiệu ứng ripple trên Android). Lưu ý: Ripple chỉ hoạt động trên Android 5+.
<Pressable
onPress={() => console.log('Đã nhấn')}
onLongPress={() => console.log('Nhấn giữ')}
onPressIn={() => console.log('Ngón tay xuống')}
onPressOut={() => console.log('Ngón tay lên')}
delayLongPress={300}
android_ripple={{ color: 'rgba(0,0,0,0.1)', borderless: false }}
style={styles.button}>
<Text>Press me</Text>
</Pressable>onPress chỉ được gọi nếu ngón tay được nhấc lên trong vùng thành phần (tính đến pressRetentionOffset). Nếu người dùng di chuyển ngón tay ra ngoài ranh giới, onPress không được kích hoạt, ngăn chặn các lần nhấn giả. onPressOut được gọi trong mọi trường hợp khi thả ra.
hitSlop là một prop của Pressable mở rộng vùng cảm ứng vượt ra ngoài ranh giới hiển thị của thành phần. Điều này rất quan trọng đối với các phần tử nhỏ: biểu tượng, hộp kiểm, nút radio. Apple HIG khuyên dùng kích thước mục tiêu cảm ứng tối thiểu là 44×44 điểm. hitSlop cho phép đáp ứng yêu cầu này mà không thay đổi kích thước hiển thị.
hitSlop chấp nhận một đối tượng { top, bottom, left, right } hoặc một số duy nhất cho tất cả các cạnh. Các giá trị được chỉ định bằng pixel logic (dp/pt). Đối với biểu tượng 24×24, nên sử dụng hitSlop ít nhất 10–12 ở mỗi cạnh để đạt được mục tiêu cảm ứng 44×44.
<Pressable
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
onPress={handleIconPress}
style={styles.iconButton}>
<Icon name="star" size={24} />
</Pressable>pressRetentionOffset — ngược lại của hitSlop: xác định vùng mà người dùng có thể di chuyển ra ngoài ranh giới thành phần mà không bị hủy nhấn. Mặc định bằng hitSlop. Nếu bạn cần duy trì nhấn khi di chuyển ra ngoài ranh giới, hãy tăng pressRetentionOffset.
Pressable so với Touchable — một câu hỏi chính khi chọn thành phần xử lý cảm ứng. TouchableOpacity, TouchableHighlight và TouchableWithoutFeedback là các thành phần cũ sẽ không bị xóa nhưng sẽ không nhận được tính năng mới. Meta khuyên dùng Pressable cho các dự án mới.
Các lợi thế chính của Pressable: API thống nhất cho tất cả các loại hiệu ứng, truy cập trạng thái pressed để tạo kiểu tùy chỉnh, hỗ trợ trạng thái hovered/focused, hitSlop và pressRetentionOffset, callback onLongPress mà không cần cấu hình thêm. TouchableOpacity chỉ phù hợp cho các thay đổi độ mờ đơn giản.
| Kịch bản | Touchable | Pressable |
|---|---|---|
| Nhấn đơn giản | TouchableOpacity | Pressable + opacity trong style |
| Làm nổi bật nền | TouchableHighlight | Pressable + backgroundColor |
| Không hiệu ứng trực quan | TouchableWithoutFeedback | Pressable với style rỗng |
| Nhấn giữ | onLongPress trên bất kỳ Touchable | onLongPress trên Pressable |
| Hoạt ảnh tùy chỉnh | Animated + onPressIn/Out | Pressable + useAnimatedStyle |
| Ripple trên Android | TouchableNativeFeedback | Pressable + android_ripple |
Pressable cho phép tạo các phần tử tương tác phức tạp với mã tối thiểu. Dưới đây là ví dụ về một nút hoạt ảnh với thay đổi tỷ lệ khi nhấn và hiệu ứng ripple trên Android. Nút như vậy thay thế sự kết hợp 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>
);
};Quan trọng: sử dụng useNativeDriver: true cho các hoạt ảnh trong Pressable. Điều này chuyển hoạt ảnh sang luồng native, ngăn chặn rụt khung hình khi nhấn nhanh. Trình điều khiển native được hỗ trợ cho transform và opacity trên tất cả các nền tảng.
Câu hỏi thường gặp
Không, Pressable có API khác. TouchableOpacity tự động áp dụng độ mờ khi nhấn. Pressable yêu cầu chỉ định kiểu rõ ràng thông qua hàm trạng thái. Việc thay thế rất đơn giản: truyền style={({ pressed }) => [{ opacity: pressed ? 0.5 : 1 }]}.
Sử dụng prop android_ripple với đối tượng { color, borderless }. Màu ripple được chỉ định ở định dạng rgba. Đối với nút tròn, sử dụng borderless: true. Ripple chỉ hoạt động trên Android 5+. Trên iOS, sử dụng hoạt ảnh tùy chỉnh.
Pressable có tính năng bảo vệ tích hợp chống nhấn vô tình khi cuộn. Nếu người dùng cuộn danh sách, onPress không được gọi. Hành vi này có thể được cấu hình qua pressRetentionOffset và delayPressIn.
Sử dụng prop onLongPress — hỗ trợ nhấn giữ tích hợp. Độ trễ có thể được cấu hình qua delayLongPress (mặc định 500 ms). Đối với menu ngữ cảnh và kéo thả, kết hợp onLongPress với onPressIn.
Có, Pressable hỗ trợ trạng thái focused cho điều hướng bàn phím trên Android TV, Apple TV và Web. Sử dụng tạo kiểu qua { focused } để hiển thị tiêu điểm. Trên thiết bị di động, trạng thái focused không áp dụng.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm