
react-native-elements SpeedDial 组件完全指南FAB 速拨菜单的实现原理与实战用法【免费下载链接】react-native-elementsCross-Platform React Native UI Toolkit项目地址: https://gitcode.com/gh_mirrors/re/react-native-elements本文以 react-native-elementsv3.4.2 文档中的 SpeedDial 组件为核心讲解如何基于 Floating Action ButtonFAB构建速拨菜单点击悬浮按钮后向上弹出一组 26 个快捷操作并深入源码剖析其动画、遮罩与事件路由机制。读完本文你将掌握 SpeedDial 的全部 Props、子组件 SpeedDial.Action 的用法以及如何在示例工程中落地一套完整的速拨菜单。一、SpeedDial 是什么设计约束与适用场景SpeedDial 是 Material Design 中 FAB 的一种扩展形态。根据 version-3.4.2 官方文档 的定义当按下时一个浮动操作按钮可以以速拨的形式展示三到六个相关操作。其交互规范包含三点关键约束数量限制只适合承载 36 个关联操作如果超过 6 个动作应当改用其他容器如列表、菜单来呈现而不是继续堆叠 SpeedDial展开后主按钮保持可见按下 FAB 后主按钮不消失而是在其上方发射出一叠相关操作项主按钮的二次点击语义在展开状态下再次点击 FAB应当要么触发其默认动作要么收起速拨菜单。在源码层面SpeedDial 组件定义 的 JSDoc 与文档描述完全一致二者互为印证。二、快速开始安装与引入SpeedDial 是 react-native-elements 包内建组件随主包一并安装无需额外依赖。引入方式有两种// 方式一从 rneui/base 引入基础版 import { SpeedDial } from rneui/base; // 方式二从 rneui/themed 引入主题版支持 ThemeProvider 定制 import { SpeedDial } from rneui/themed;主题版的导出由 packages/themed/src/index.ts 统一维护而组件本身定义在 packages/base/src/SpeedDial/index.tsx。注意该入口文件使用Object.assign把SpeedDial.Action静态挂载到SpeedDial上const DefaultSpeedDial Object.assign(SpeedDial, { Action: SpeedDialAction, }); export { DefaultSpeedDial as SpeedDial };这解释了为什么你可以直接用SpeedDial.Action的写法而不需要单独引入子组件。三、基础用法一个可开合的最小示例文档给出的最小可用示例完整如下import React from react; import { SpeedDial } from react-native-elements; export default () { const [open, setOpen] React.useState(false); return ( SpeedDial isOpen{open} icon{{ name: edit, color: #fff }} openIcon{{ name: close, color: #fff }} onOpen{() setOpen(!open)} onClose{() setOpen(!open)} SpeedDial.Action icon{{ name: add, color: #fff }} titleAdd onPress{() console.log(Add Something)} / SpeedDial.Action icon{{ name: delete, color: #fff }} titleDelete onPress{() console.log(Delete Something)} / /SpeedDial ); };几个关键点的实战说明isOpen必须受控SpeedDial 是一个完全受控组件展开状态由外层useState驱动组件自身不维护内部开关状态icon与openIcon成对出现收起时 FAB 显示icon如编辑图标展开时切换为openIcon如关闭图标形成清晰的状态反馈onOpen/onClose负责状态翻转主按钮在收起态被点击触发onOpen在展开态被点击触发onClose点击遮罩区域同样触发onClose。事件路由一个 onPress 的两种身份在 SpeedDial.tsx 中主 FAB 的onPress是动态分发的FAB style{[styles.fab]} icon{isOpen ? openIcon : icon} theme{theme} {...rest} onPress{isOpen ? onClose : onOpen} /即展开状态下按主按钮 收起菜单onClose收起状态下按主按钮 展开菜单onOpen。这就是文档所述再次点击要么触发默认动作、要么关闭速拨的底层实现你可以在onClose回调里额外拼接业务逻辑来实现默认动作。四、SpeedDial 全部 Props 详解以下参数说明以 props/speeddial.md 为基准并结合源码补充实现细节。4.1 核心 Props参数类型默认值说明isOpenbooleanfalse是否展开操作栈必填openIconIconNodenone操作栈展开时 FAB 上显示的图标transitionDurationnumber150展开/收起过渡动画时长单位毫秒onOpenfunctionnone组件请求展开时触发的回调onClosefunctionnone组件请求收起时触发的回调4.2 附加 Props源码中另有实现在 SpeedDialProps 接口 中还声明了文档 Props 页之外的几个参数参数类型说明overlayColorstring展开时背景遮罩的颜色默认使用theme.colors.black的 60% 透明度labelPressableboolean是否允许点击操作项的标题文本默认只有圆形按钮可点backdropPressablePropsPressableProps透传给遮罩层Pressable的属性childrenReact.ReactElement[]即一组SpeedDial.ActionoverlayColor的默认值并非写死的色值而是在渲染时动态计算见 SpeedDial.tsxbackgroundColor: overlayColor || Color(theme?.colors?.black).alpha(0.6).rgb().toString(),如果你想在展开时去掉深色遮罩例如场景本身是模态页传overlayColortransparent即可示例工程正是这样做的见下文第六节。4.3 继承自 FAB 的全部 PropsSpeedDial 的 Props 接口extends FABProps因此除size外它还接收 FAB 的全部能力FAB 文档见 fab.md参数类型默认值说明placementleft \| rightnoneFAB 停靠在底部左侧或右侧colorstring主题的 secondary 色FAB 背景色visiblebooleanfalseFAB 可见性带淡入缩放动画upperCasebooleanfalse扩展标签文本是否转大写styleStylePropViewStyle—自定义布局样式完整说明见 props/fab.md。其中placement是实战中最常用的参数它同时影响动作堆叠的对齐方向见 SpeedDial.tsx 中的alignItems: placement left ? flex-start : flex-end以及内部 FAB 的绝对定位。五、子组件 SpeedDial.Action单条操作项每个操作项通过SpeedDial.Action声明其 Props 接口为OmitFABProps, size即继承 FAB 全部 Props、唯独强制 size——因为操作项统一使用小尺寸圆形按钮SpeedDial.Action.tsxFAB {...actionProps} onPress{onPress} sizesmall style{[actionProps.style]} /常用属性SpeedDial.Action icon{{ name: add, color: #fff }} // 图标IconNode titleAdd // 左侧扩展标签文本 titleStyle{styles.myTitle} // 自定义标签样式 onPress{() handleAdd()} // 点击回调 /5.1 标题标签的默认样式未自定义时标题渲染为白底黑字的小圆角标签SpeedDial.Action.tsxtitle: { backgroundColor: white, color: black, borderRadius: 5, paddingHorizontal: 12, paddingVertical: 6, marginVertical: 8, marginHorizontal: 16, elevation: 2, }5.2 labelPressable 的点击行为差异这是容易踩坑的一点默认情况下只有圆形图标按钮本身响应onPress点击文字标签不会触发回调。只有当父级SpeedDial设置labelPressable时整个操作项含标题才可点击见 SpeedDial.Action.tsxPressable onPress{labelPressable ? onPress : undefined} ... 同时SpeedDial在克隆子元素时会自动把placement与labelPressable透传给每个 ActionSpeedDial.tsx因此子组件无需重复声明。六、进阶实战来自示例工程的双侧速拨菜单仓库自带的示例应用 example/src/views/speedDial.tsx 演示了更完整的用法左右各放一个 SpeedDial、打开透明遮罩并启用labelPressableconst [open, setOpen] React.useState(false); SpeedDial isOpen{open} labelPressable placementright overlayColortransparent icon{{ name: edit, color: #fff }} openIcon{{ name: close, color: #fff }} onOpen{() setOpen(!open)} onClose{() setOpen(!open)} SpeedDial.Action icon{{ name: add, color: #fff }} titleAdd onPress{() console.log(Added Event)} / SpeedDial.Action icon{{ name: delete, color: #fff }} titleDelete onPress{() console.log(Delete Event)} / /SpeedDial SpeedDial placementleft isOpen{open} overlayColortransparent labelPressable /* ... */ {/* 三个 Actionadd / add / delete */} /SpeedDial值得注意的工程化细节placementleft时操作项会自动改为flexDirection: row-reverse标题出现在按钮左侧SpeedDial.Action.tsx主 FAB 默认带 16 的外边距styles.fab见 SpeedDial.tsx并包在SafeAreaView内可安全适配刘海屏底部多个 Action 会自下而上堆叠且因为默认外层Animated.View设置pointerEvents{isOpen ? auto : none}收起状态下的 Action 不会拦截手势SpeedDial.tsx。七、源码级原理动画、遮罩与安全区7.1 展开动画Animated.stagger 交错弹入每个 Action 对应一个独立的Animated.Value初始值与isOpen同步当状态变化时用Animated.stagger(50, ...)让动作依次交错弹出单次动画时长即transitionDuration默认 150ms并开启原生驱动SpeedDial.tsxAnimated.stagger( 50, animations.current .map((animation) Animated.timing(animation, { toValue: Number(isOpen), duration: transitionDuration, useNativeDriver: true, }) ) [isOpen ? reverse : sort]() ).start();这里有一个精巧的细节展开时动画顺序reverse从最后一个 Action 开始先动收起时sort从第一个开始先收视觉上表现为展开像扇面推开、收起像依次回缩。每个 Action 的scale与opacity都由该动画值驱动。7.2 遮罩层独立 Pressable 捕获点击容器最底层是一个铺满全屏的Pressable其onPress直接绑定onClose只有isOpen为 true 时pointerEvents才为autoSpeedDial.tsx。也就是说点击屏幕上除菜单外的任意区域即可收起速拨这是该组件交互完整性的关键一环。7.3 安全区与容器布局最外层View使用StyleSheet.absoluteFillObject铺满屏幕并把内容压到底部justifyContent: flex-end内部SafeAreaView按placement决定左对齐或右对齐。从源码结构看SpeedDial 设计为屏幕级悬浮容器应当作为页面最顶层的兄弟节点使用而不是嵌套在普通流式布局中。八、测试保障行为如何被验证组件仓库为 SpeedDial 提供了两层测试可用于理解其行为契约SpeedDial.test.tsx以isOpen{true}渲染两个 Action做整体快照比对保证结构与样式不被意外破坏SpeedDial.Action.test.tsx用testing-library/react-native的fireEvent模拟点击标题文本断言onPress被触发——注意这里测试的是渲染独立的SpeedDial.Action无父级labelPressable时标题默认不可点但按钮本身可点测试经由getByText(Delete)触发的是整个 Action 容器。主题版rneui/themed同样带有对应测试 packages/themed/src/SpeedDial/tests/SpeedDial.test.tsx可放心在主题化项目中使用。九、使用限制与最佳实践小结动作数量控制在 36 个超过 6 个请改用其他呈现方式如ActionSheet、列表受控状态务必通过useState/useReducer维护isOpen并把onOpen/onClose与状态更新绑定否则无法开合图标语义icon与openIcon建议成对配置用编辑 → 关闭这类状态反差图标提升可用性点击热区需要用户点击文字标签时给父级SpeedDial加labelPressable遮罩定制不希望展开时盖住背景用overlayColortransparent位置对齐通过placementleft | right控制停靠方向操作项与标签会自动镜像布局。至此从 Props 到动画源码、从单按钮到双侧速拨你已经具备在 react-native-elements 项目中独立实现并定制 SpeedDial 的完整能力。更详细的参数参考可继续查阅 SpeedDial 文档 与 FAB 文档。【免费下载链接】react-native-elementsCross-Platform React Native UI Toolkit项目地址: https://gitcode.com/gh_mirrors/re/react-native-elements创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考