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 年 9 月)中引入。根据 Meta 的数据(2026),React Native 上 70% 的新项目使用 Pressable 代替 Touchable 组件。Pressable 解决了 Touchable 的主要问题——API 碎片化以及为了不同效果而需要在组件之间切换的问题。
与 TouchableOpacity 不同,后者的按压效果是固定的(改变透明度),Pressable 提供一个接收当前状态的函数。开发者自己决定如何在视觉上响应触摸:改变颜色、缩放、阴影或效果的组合。这提供了对用户体验的完全控制。
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>Pressable API 包含四个主要回调函数:onPress(完整按压并释放)、onLongPress(长按)、onPressIn(触摸开始)和 onPressOut(触摸结束)。onPressIn 和 onPressOut 的组合可以创建自定义动画。
额外的 props:delayLongPress(长按延迟,默认 500 毫秒)、pressRetentionOffset(超出此区域按压取消)、android_ripple(Android 上的 ripple 效果)。重要: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 — 是 Pressable 的一个 prop,用于将触摸区域扩展到组件可见边界之外。这对于小元素至关重要:图标、复选框、单选按钮。Apple HIG 建议触摸目标的最小尺寸为 44x44 点。hitSlop 可以在不改变视觉尺寸的情况下满足这一要求。
hitSlop 接受一个对象 { top, bottom, left, right } 或一个单一数值针对所有边。值以逻辑像素(dp/pt)指定。对于 24x24 的图标,建议每边 hitSlop 至少 10-12,以达到 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 与 Touchable — 选择触摸处理组件时的关键问题。TouchableOpacity、TouchableHighlight 和 TouchableWithoutFeedback 是已过时的组件,它们不会被删除,但不会获得新功能。Meta 建议新项目使用 Pressable。
Pressable 的主要优势:统一的 API 支持所有类型的效果、可访问 pressed 状态以进行自定义样式、支持 hovered/focused 状态、hitSlop 和 pressRetentionOffset、无需额外配置即可使用 onLongPress 回调函数。TouchableOpacity 仅适合简单的透明度变化。
| 场景 | Touchable | Pressable |
|---|---|---|
| 简单按压 | TouchableOpacity | Pressable + style 中的 opacity |
| 背景高亮 | TouchableHighlight | Pressable + backgroundColor |
| 无视觉效果 | TouchableWithoutFeedback | 带空 style 的 Pressable |
| 长按 | 任何 Touchable 上的 onLongPress | Pressable 上的 onLongPress |
| 自定义动画 | Animated + onPressIn/Out | Pressable + useAnimatedStyle |
| Android 上的 Ripple | TouchableNativeFeedback | Pressable + android_ripple |
Pressable 可以用最少的代码创建复杂的交互元素。下面是一个动画按钮的示例,在按压时改变缩放并在 Android 上显示 ripple 效果。这样的按钮可以替代 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>
);
};重要:在 Pressable 中为动画使用 useNativeDriver: true。这将动画移到原生线程,防止快速按压时的帧率下降。对于 transform 和 opacity,原生驱动程序在所有平台上都得到支持。
常见问题
不能,Pressable 有不同的 API。TouchableOpacity 在按压时自动应用透明度。Pressable 需要通过状态函数 明确指定样式。替换很简单:传递 style={({ pressed }) => [{ opacity: pressed ? 0.5 : 1 }]}。
使用 android_ripple prop,带一个 { color, borderless } 对象。Ripple 颜色以 rgba 格式指定。对于圆形按钮,使用 borderless: true。Ripple 仅在 Android 5+ 上工作。在 iOS 上使用自定义动画。
Pressable 具有内置防误触保护。如果用户滚动列表,onPress 不会被调用。可以通过 pressRetentionOffset 和 delayPressIn 配置此行为。
使用 onLongPress prop——内置支持长按。延迟通过 delayLongPress(默认 500 毫秒)配置。对于上下文菜单和拖拽,将 onLongPress 与 onPressIn 组合使用。
是的,Pressable 在 Android TV、Apple TV 和 Web 上支持 focused 状态的键盘导航。使用 { focused } 进行样式设置以显示聚焦。在移动设备上,focused 状态不相关。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。