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 (องค์ประกอบที่โฟกัสแป้นพิมพ์) แต่ละสถานะจะเรียก callback ที่เกี่ยวข้องและส่งต่อไปยังฟังก์ชันสไตล์และฟังก์ชันเรนเดอร์ลูก
| สถานะ | เงื่อนไข | การตอบสนองทั่วไป |
|---|---|---|
| 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>Pressable API ประกอบด้วย callback หลักสี่ตัว: 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 แนะนำขนาดเป้าหมายสัมผัสขั้นต่ำ 44×44 จุด hitSlop ช่วยให้ปฏิบัติตามข้อกำหนดนี้โดยไม่เปลี่ยนขนาดที่มองเห็น
hitSlop รับออบเจ็กต์ { top, bottom, left, right } หรือตัวเลขเดียวสำหรับทุกด้าน ค่าจะถูกระบุเป็นพิกเซลเชิงตรรกะ (dp/pt) สำหรับไอคอน 24×24 แนะนำให้ใช้ hitSlop อย่างน้อย 10–12 ในแต่ละด้านเพื่อให้ได้เป้าหมายสัมผัส 44×44
<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 เทียบกับ Touchable — คำถามสำคัญเมื่อเลือกคอมโพเนนท์สำหรับจัดการการสัมผัส TouchableOpacity, TouchableHighlight และ TouchableWithoutFeedback เป็นคอมโพเนนท์เก่าที่จะไม่ถูกลบออก แต่จะไม่ได้รับฟีเจอร์ใหม่ Meta แนะนำ Pressable สำหรับโปรเจกต์ใหม่
ข้อได้เปรียบหลักของ Pressable: API แบบรวมศูนย์สำหรับเอฟเฟกต์ทุกประเภท การเข้าถึงสถานะ pressed สำหรับจัดแต่งสไตล์แบบกำหนดเอง การรองรับสถานะ hovered/focused, hitSlop และ pressRetentionOffset, callback 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 ซึ่งจะย้ายแอนิเมชันไปยังเธรดเนทีฟ ป้องกันการหลุดของเฟรมระหว่างการกดเร็ว native driver รองรับ transform และ opacity บนทุกแพลตฟอร์ม
คำถามที่พบบ่อย
ไม่ได้ 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) สำหรับเมนูบริบทและการลากและวาง ให้รวม onLongPress กับ onPressIn
ใช่ Pressable รองรับสถานะ focused สำหรับการนำทางด้วยแป้นพิมพ์บน Android TV, Apple TV และ Web ใช้การจัดแต่งสไตล์ผ่าน { focused } เพื่อแสดงโฟกัส บนอุปกรณ์มือถือ สถานะ focused ไม่เกี่ยวข้อง
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ