Pressto交互状态解析:isPressed、isToggled、isSelected如何让按钮拥有记忆
【免费下载链接】presstoYour React Native app deserves better tap interactions.项目地址: https://gitcode.com/gh_mirrors/pre/pressto
Pressto 是一个运行在主线程上的 React Native 按钮动画库,通过内置的 isPressed、isToggled、isSelected 三种交互状态,让按钮既能给出"按下去的瞬间反馈",又能"记住"开关与选中的持久状态,全程无需手写 useState。本文带你逐个解析这三个状态的工作机制,并用 3 步写出带记忆的按钮。
为什么按钮需要"记忆"?
React Native 按钮的一个常见痛点:手指按下时,希望按钮有"被按下"的缩放或变暗反馈;手指抬起后,又希望部分按钮记住状态——比如"已收藏"还是"未收藏"、Tab 当前选中哪一个。
Pressto 的巧妙之处在于:它把三种状态直接封装进每个 pressable 组件,你在动画函数里直接读取即可,状态切换全部由库自动维护。
| 状态 | 生命周期 | 触发时机 | 是否持久 | 典型场景 |
|---|---|---|---|---|
| isPressed | 瞬时 | 手指按下 → 抬起 | ❌ | 按压缩放、变暗反馈 |
| isToggled | 持久 | 每次点击自动翻转 | ✅ | 开关、收藏、静音 |
| isSelected | 持久 | 组内最后被点中 | ✅ | Tab 切换、单选列表 |
isPressed:手指按下的那一刻
isPressed 最直观:手指按下瞬间为 true,抬起即恢复 false,并驱动 0→1 的动画进度值 progress,内置的缩放、透明度假动画就是靠它。
在源码 src/pressables/base.tsx 中,active共享值在按下(onPressIn)时被设为 true,而onEnded、onCancelled、onFailed事件统一映射到 onPressOut——这意味着"手指滑出按钮区域"或"长按失败"都会视为抬起,按钮不会卡在按压状态。
另外在 Web 平台启用activateOnHover后,鼠标悬停也会激活按压状态,让桌面端同样有动效反馈。
isToggled:每次点击翻转的开关记忆
isToggled 是"记忆"的核心:每点一次就在 true / false 之间自动翻转,并且跨点击保留。初始值可由initialToggled属性设置(默认 false),适合"默认已静音"之类的场景。
翻转逻辑就在 src/pressables/base.tsx 的按下处理器里:每次成功点击执行isToggled.set(!isToggled.get()),你完全不用手动管理状态。这个行为有完善的单元测试守护,见 src/tests/handlers.test.tsx——连续点击三次,状态依次为 true、false、true。
isSelected:组内"最后选中"的标记
isSelected 专为按钮组设计:组内任意一个按钮被点击后,只有它是 true,之前选中的自动变 false。你不需要维护 selected 索引或数组,库内部用共享的"最后被触碰"标识做了这件事。
其派生逻辑同样在 src/pressables/base.tsx 中:将 src/provider/context.ts 里 PressablesGroupContext 提供的lastTouchedPressable共享值与自身唯一 ID 比对,相等即处于选中态。
三步写出带记忆的按钮
- 创建自定义 pressable:用
createAnimatedPressable包装一个动画函数(定义于 src/pressables/hoc.tsx)。 - 读取三个状态:从 options 中解构 isPressed、isToggled、isSelected。
- 交给 withAnimation:options 自带预配置的动画函数,颜色和数值变化都会自动平滑过渡。
一个最小的切换按钮示例:
const ToggleButton = createAnimatedPressable((progress, options) => { 'worklet'; const { isPressed, isToggled, isSelected, withAnimation } = options; return { backgroundColor: withAnimation(isToggled ? '#4CAF50' : '#2196F3'), opacity: isPressed ? 0.8 : 1, borderWidth: isSelected ? 3 : 0, }; });⚠️ 注意:动画函数首行必须写'worklet';指令,否则动画无法运行在主线程。
除了在动画函数里用,事件回调也能读取这三个状态:onPress/onPressIn/onPressOut都会收到{ isPressed, isToggled, isSelected, metadata }快照(类型定义见 src/provider/context.ts),非常适合埋点上报或触发副作用。
快速参考
- 完整状态与属性说明:README.md 的 API Reference 部分
- 交互状态可运行的示例应用:example/app/index.tsx、example/app/screen.tsx
- 状态行为的单元测试:src/tests/handlers.test.tsx
【免费下载链接】presstoYour React Native app deserves better tap interactions.项目地址: https://gitcode.com/gh_mirrors/pre/pressto
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考