十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用 react-native-reanimated 打造悬浮操作按钮(Floating Action Button):共享值驱动的展开动画实战

用 react-native-reanimated 打造悬浮操作按钮(Floating Action Button):共享值驱动的展开动画实战 用 react-native-reanimated 打造悬浮操作按钮Floating Action Button共享值驱动的展开动画实战【免费下载链接】react-native-reanimatedReact Natives Animated library reimplemented项目地址: https://gitcode.com/GitHub_Trending/re/react-native-reanimated悬浮操作按钮FABFloating Action Button是移动端界面中承载主操作/常用操作的经典交互组件。本文以 react-native-reanimated 官方文档示例 floating-action-button.md 及其完整实现 FloatingActionButton.js 为骨架深入讲解如何用useSharedValue监听按钮展开状态、用withSpring/withTiming/withDelay组合驱动次级按钮的位移与缩放、以及如何通过索引计算实现按钮的阶梯式出场。读完后你将能独立实现一个零额外依赖、在 UI 线程上丝滑运行的 FAB 组件。组件效果与设计思路本示例实现了一个居中的圆形 主按钮按下后三个次级按钮M、W、S沿垂直方向向上依次弹出主按钮的 图标同步旋转 45° 变为 ×再次点击则所有按钮复位。完整运行效果可参考仓库中的录制视频 fab_android.mov 与 fab_ios.mov对应 iOS 端。整个组件由两个部分构成App根组件持有共享值isExpanded负责状态切换与主按钮的 图标动画FloatingActionButton可复用子组件接收isExpanded、index、buttonLetter三个 props根据展开状态与自身索引计算各自的位移动画和缩放延迟。用 useSharedValue 监听展开状态避免不必要的重渲染原文档首先强调我们使用 共享值shared values 来监测按钮是否展开。useSharedValue返回的共享值是一个普通 JavaScript 对象修改它的.value属性不会触发 React 重新渲染因此频繁的动画状态切换不会带来组件树的重绘开销与此同时数据会在 JS 线程与 UI 线程之间自动同步动画逻辑可以直接运行在 UI 线程上详见 glossary.mdx 与 useSharedValue.mdx 文档。示例中状态定义与切换逻辑如下对应源码 FloatingActionButton.jsconst isExpanded useSharedValue(false); const handlePress () { isExpanded.value !isExpanded.value; };源码级验证useSharedValue 的实现从源码看useSharedValue通过useState惰性初始化一个由makeMutable创建的 mutable 对象并在组件卸载时调用cancelAnimation清理动画见 hook/useSharedValue.tsexport function useSharedValueValue( initialValue: Value | (() Value) ): SharedValueValue { const [mutable] useState(() { const value typeof initialValue function ? (initialValue as () Value)() : initialValue; return makeMutable(value); }); useEffect(() { return () { cancelAnimation(mutable); }; }, [mutable]); return mutable; }值得注意的细节useSharedValue(false)的初始值可以是任意 JS 值number、string、boolean、数组、对象本示例直接传入布尔值作为展开状态共享值仅作为状态开关真正的动画计算全部由useAnimatedStyle中的 worklet 在 UI 线程完成这正是不引发 React 重渲染又能驱动动画的关键卸载时cancelAnimation会停止尚未完成的动画避免内存泄漏。主按钮的 图标用 interpolate 与 withTiming 实现旋转与平移当isExpanded翻转时主按钮的 图标需要平滑旋转 45°同时轻微右移形成 × 的视觉形态。示例使用interpolate将布尔状态映射为位移量并用withTiming驱动对应源码 FloatingActionButton.jsconst plusIconStyle useAnimatedStyle(() { const moveValue interpolate(Number(isExpanded.value), [0, 1], [0, 2]); const translateValue withTiming(moveValue); const rotateValue isExpanded.value ? 45deg : 0deg; return { transform: [ { translateX: translateValue }, { rotate: withTiming(rotateValue) }, ], }; });这里的三个关键点interpolate将isExpanded布尔值经Number()转为 0/1映射到[0, 2]的位移区间实现图标 2 个单位的水平偏移rotate字符串动画这正是文档中提到的 可动画值animatable values——Reanimated 支持45deg、21%、颜色字符串等特定格式的字符串动画无需手动处理角度插值withTiming默认基于时长与缓动函数easing执行动画让旋转和位移平滑过渡到目标值。次级按钮用索引计算延迟实现阶梯式弹出三个次级按钮复用同一个FloatingActionButton组件通过index1/2/3控制各自的位移与出场延迟。索引越大按钮出现得越晚、最终停靠的位置越高形成一列按钮的视觉层次对应源码 FloatingActionButton.jsconst FloatingActionButton ({ isExpanded, index, buttonLetter }) { const animatedStyles useAnimatedStyle(() { const moveValue isExpanded.value ? OFFSET * index : 0; const translateValue withSpring(-moveValue, SPRING_CONFIG); const delay index * 100; const scaleValue isExpanded.value ? 1 : 0; return { transform: [ { translateY: translateValue }, { scale: withDelay(delay, withTiming(scaleValue)), }, ], }; }); return ( AnimatedPressable style{[animatedStyles, styles.shadow, styles.button]} Animated.Text style{styles.content}{buttonLetter}/Animated.Text /AnimatedPressable ); };位移withSpring 与 OFFSET * index示例定义了const OFFSET 60;每个按钮的向上位移量是OFFSET * indexindex1 位移 60、index2 位移 120、index3 位移 180按钮沿 Y 轴负方向向上依次排开。位移动画使用withSpring配合自定义弹簧配置const SPRING_CONFIG { duration: 1200, overshootClamping: true, dampingRatio: 0.8, };该配置对应 Reanimated 中基于时长 阻尼比的弹簧配置风格。从源码看spring 动画支持mass/damping/stiffness与duration/dampingRatio两套配置体系仓库预置了多组弹簧配置常量见 animation/spring/springConfigs.tsovershootClamping: true限制弹簧不得越过目标值禁止过冲回弹适合按钮停靠场景——用户期望按钮精确停在目标位置而不是来回震荡dampingRatio: 0.8接近临界阻尼1.0的阻尼比让运动快速趋于稳定且不产生明显过冲若不提供该配置Reanimated 默认使用Reanimated3DefaultSpringConfigdamping: 10, mass: 1, stiffness: 100或Reanimated3DefaultSpringConfigWithDurationduration: 1333, dampingRatio: 0.5。缩放withDelay withTiming 实现错峰出场scaleValue在展开时为 1、收起时为 0缩放动画用withTiming执行而delay index * 100毫秒通过withDelay施加延迟使 index1 的按钮先出现、index2 后出现、index3 最后出现形成流畅的阶梯感scale: withDelay(delay, withTiming(scaleValue)),从源码看withDelay是一个高阶动画修饰器higher-order animation modifier在等待期内它不推进目标动画一旦now - startTime delayMs便调用子动画的onStart/onFrame真正开始执行见 animation/delay.ts。delayMs即延迟毫秒数第二参数是被延迟的动画对象还支持第三个可选参数reduceMotion以响应系统的减弱动态效果设置。关键配套细节AnimatedPressable将 Pressable 转换为可动画组件示例中主按钮与次级按钮都使用AnimatedPressable它是通过Animated.createAnimatedComponent(Pressable)创建的。Reanimated 内置了Animated.View、Animated.Text、Animated.ScrollView等组件而对第三方/原生组件如Pressable则需要用createAnimatedComponent包装使其 style 与 props 可被动画驱动见 glossary.mdxconst AnimatedPressable Animated.createAnimatedComponent(Pressable);样式分层阴影、绝对定位与 zIndexStyleSheet中通过绝对定位把三个次级按钮叠放在主按钮上方position: absolute宽高 40主按钮宽高 56 并设zIndex: 1styles.shadow为按钮提供一致的投影zIndex: -2保证次级按钮位于主按钮之下。子组件将useAnimatedStyle返回的动画样式与静态样式合并style{[animatedStyles, styles.shadow, styles.button]}。总结与延伸本示例集中展示了 react-native-reanimated 在组件动画上的四个核心能力可作为后续实战的范式能力用到的 API作用状态管理useSharedValue持有展开状态跨线程同步且不触发 React 重渲染值映射interpolate将布尔状态映射为位移量动画函数withSpring、withTiming弹簧位移与时长缓动缩放动画修饰器withDelay按索引错峰延迟实现阶梯出场在此基础上你还可以结合withSequence链式动画、withRepeat循环动画与布局动画等能力扩展更复杂的交互共享值与动画函数的完整语义可进一步参考 glossary.mdx 与 withSpring.mdx、withTiming.mdx、withDelay.mdx 等文档。完整可运行的示例源码位于 docs/docs-reanimated/static/examples/FloatingActionButton.js。【免费下载链接】react-native-reanimatedReact Natives Animated library reimplemented项目地址: https://gitcode.com/GitHub_Trending/re/react-native-reanimated创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表