mcpField
E
expo-native-ui

expo-native-ui

github.com/expo设计与 UI3.5k32.7k 次安装今天更新
代码仓库

关于 expo-native-ui

expo-native-ui 是面向 Expo 应用开发者和编码 Agent 的界面开发技能,涵盖布局、样式、平台规范及原生 UI 组件选择建议。

主要功能

  1. 01Expo Router 布局指导
  2. 02平台专属样式规范
  3. 03原生语义颜色建议
  4. 04Expo Go 与构建建议
  5. 05UI 参考资料

适用场景

  1. 01组织 Expo 应用页面
  2. 02应用 iOS 与 Android 设计规范
  3. 03判断使用 Expo Go 还是自定义构建

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/expo/skills --skill expo-native-ui

安装后在 Claude Code 中输入/expo-native-ui确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
references/
controls.md
gradients.md
icons.md
media.md
storage.md
visual-effects.md
webgpu-three.md

详细介绍

Expo 原生 UI 指南

对于路由、链接、堆栈、标签页、模态框、底部面板和标题栏,请使用 expo-router 技能。对于任何动效——进入/退出、手势、弹簧动画、键盘驱动的 UI——请使用 expo-animation 技能。

选择任何 UI 组件之前,请先查看 expo-ui。 @expo/ui 提供原生组件——BottomSheet、Button、Picker、Slider、Menu、Section、Switch、SegmentedControl 等——在 iOS 上以真正的 SwiftUI、在 Android 上以 Jetpack Compose 渲染,SDK 56+ 的 Expo Go 中即可使用,无需自定义构建。请加载 expo-ui 技能,先找到合适的组件,再考虑使用 React Native 内置组件或社区库。本技能(expo-native-ui)涵盖周边结构:Expo Router 导航、布局、样式和视觉效果。

参考资料

按需查阅以下资源:

references/
  controls.md            Native iOS: Switch, Slider, SegmentedControl, DateTimePicker, Picker
  gradients.md           CSS gradients via experimental_backgroundImage (New Arch only)
  icons.md               SF Symbols via expo-symbols SymbolView: names, weights, animations; Material icons on Android
  media.md               Camera, audio, video, and file saving
  storage.md             SQLite, AsyncStorage, SecureStore
  visual-effects.md      Blur (expo-blur) and liquid glass (expo-glass-effect)
  webgpu-three.md        3D graphics, games, GPU visualizations with WebGPU and Three.js

运行应用

重要:创建自定义构建前,务必先尝试使用 Expo Go。

大多数 Expo 应用无需任何自定义原生代码即可在 Expo Go 中运行。运行 npx expo run:ios 或 npx expo run:android 之前:

  1. 从 Expo Go 开始:运行 npx expo start,并使用 Expo Go 扫描二维码
  2. 检查功能是否正常:在 Expo Go 中全面测试应用
  3. 仅在必要时创建自定义构建——见下文
需要自定义构建的情况

仅在使用以下功能时,才需要运行 npx expo run:ios/android 或 eas build:

  • 本地 Expo 模块(modules/ 中的自定义原生代码)
  • Apple 目标(通过 @bacons/apple-targets 实现的小组件、App Clip、扩展)
  • Expo Go 未包含的第三方原生模块
  • 无法在 app.json 中配置的自定义原生配置
Expo Go 可用的情况

Expo Go 开箱即支持多种功能:

  • 大多数 expo-* 包(相机、位置、传感器、sqlite 等)——但并非全部:自 SDK 53 起,Android 上的 Expo Go 不支持远程推送通知;某些包需要 Expo Go 未打包的原生能力(例如 WebGPU——参见 references/webgpu-three.md)
  • Expo Router 导航和深层链接
  • 大多数 UI 库(reanimated、gesture handler 等)

如果不确定,请先尝试 Expo Go。 创建自定义构建会增加复杂度、减慢迭代速度,并且需要配置 Xcode/Android Studio。

代码风格

  • 注意字符串是否正确闭合。确保对嵌套反引号进行转义;切勿忘记正确转义引号。
  • 始终在文件顶部使用导入语句。
  • 文件名始终使用 kebab-case,例如 comment-card.tsx
  • 文件名中不得使用特殊字符
  • 配置 tsconfig.json 使用路径别名,并在重构时优先使用别名,而非相对导入。

库偏好

  • 对于任何表单、选择器、滑块、切换开关、菜单或分组表单区域:优先使用 @expo/ui(参见 expo-ui 技能),再考虑 React Native 内置组件或社区库——它会渲染原生 SwiftUI/Compose,并且可在 SDK 56+ 的 Expo Go 中使用。对于分组/设置样式的行(数量较少且固定),使用 @expo/ui 的 List + ListItem。对于较大或长度未知的滚动列表(信息流、搜索结果、目录),使用 FlatList 或 FlashList——@expo/ui 的 List 不支持虚拟化。
  • 切勿使用已从 React Native 移除的模块,例如 Picker、WebView、SafeAreaView 或 AsyncStorage
  • 切勿使用旧版 expo-permissions
  • 使用 expo-audio,而不是 expo-av
  • 使用 expo-video,而不是 expo-av
  • 在 iOS 上使用 expo-symbols(SymbolView)显示 SF Symbols,而不是 @expo/vector-icons——参见 references/icons.md。SF Symbols 仅适用于 Apple 平台:在 Android 上,每个图标都必须有 Material 来源(NativeTabs 触发器使用 md 属性;屏幕内选项参见 icons.md 中的“Android: Material Icons”),切勿只使用 SF 图标
  • 使用 react-native-safe-area-context,而不是 React Native 的 SafeAreaView
  • 使用 process.env.EXPO_OS,而不是 Platform.OS
  • 使用 React.use,而不是 React.useContext
  • 使用 expo-image 的 Image 组件,而不是内置元素 img
  • 使用 expo-glass-effect 实现液态玻璃背景
  • 使用 expo-router 中的 Color 获取原生语义颜色,而不是原始的 PlatformColor(类型安全,并会自动适配浅色/深色模式)
  • 在 SDK 56+ 中,切勿直接从 @react-navigation/* 导入——改用 expo-router/react-navigation(涵盖 @react-navigation/native、/core、/elements、/routers)

响应式布局

  • 带有可滚动内容的屏幕应使用 ScrollView 包裹。根元素为 FlatList/FlashList 的屏幕不得再添加外层 ScrollView(列表本身就是滚动容器),而全屏显示的屏幕(相机、地图、画布)则无需使用
  • 使用 <ScrollView contentInsetAdjustmentBehavior="automatic" />,而不是 <SafeAreaView>,以更智能地处理安全区域内边距
  • FlatList 和 SectionList 也应设置 contentInsetAdjustmentBehavior="automatic"
  • 使用 Flexbox,而不是 Dimensions API
  • 始终优先使用 useWindowDimensions,而不是 Dimensions.get(),来测量屏幕尺寸

行为

  • 在 iOS 上按需使用 expo-haptics,带来更令人愉悦的体验
  • 使用内置触感反馈的视图,例如 React Native 的 <Switch /> 和 @react-native-community/datetimepicker
  • 当 Stack 路由包含可滚动内容时,将 ScrollView(或 FlatList)作为路由内的第一个组件,并设置 contentInsetAdjustmentBehavior="automatic"
  • 对包含可复制数据的文本使用 <Text selectable /> 属性
  • 考虑将较大的数字格式化为 1.4M 或 38k 这样的形式
  • 除非在 webview 或 Expo DOM 组件中,否则绝不使用 img 或 div 等内置元素
  • 每个加载数据的屏幕都有四种状态(加载、错误、空、内容)——首次加载仍在进行时,绝不显示空状态;相关规则见 expo-data-fetching 技能
  • 对可滚动表单和搜索结果,使用 keyboardShouldPersistTaps="handled",让控件响应首次点击,并允许未处理的点击关闭键盘。只有在未处理的点击也应保持键盘打开时,才使用 "always"
  • 表单的主要操作绝不能被键盘遮挡。对于需要跟踪键盘实际边框的 UI,请加载 expo-animation 技能中的键盘方案(react-native-keyboard-controller)——绝不使用 Keyboard.addListener 配合计时动画
  • 每个启用的控件都必须执行其所声明的操作:搜索应筛选结果,Save 应提交编辑内容,设置应影响行为。空处理程序和成功提示不是实现;如果用户要求的是原型,本地状态就足够
  • 对于异步保存,按 expo-data-fetching 的要求保留草稿并处理待处理和失败状态;保存成功前不要关闭表单

在宣布屏幕完成前,完整走查其主要任务,包括加载或保存时的一次失败及恢复流程。检查键盘操作和返回/关闭行为。测试较长的标题、缺失的图片、无搜索结果以及较大的系统字体;确保所需操作始终可用。报告已测试的内容以及无法运行的内容。

样式

遵循各平台自身的设计语言:iOS 上采用 Apple Human Interface Guidelines,Android 上采用 Material Design 3。绝不要让一个平台套用另一个平台的风格——iOS 布局中不要使用 FAB 或波纹效果;Android 上不要手工构建 iOS 风格的界面元素(返回尖括号、大标题文本、iOS 风格的开关)。

通用样式规则

  • 优先使用 flex gap,而非 margin 和 padding 样式
  • 尽可能优先使用 padding,而非 margin
  • 始终考虑安全区域,可通过 Stack 标题栏、标签栏或 ScrollView/FlatList 的 contentInsetAdjustmentBehavior="automatic" 实现
  • 确保顶部和底部的安全区域内边距都得到考虑
  • 除非复用样式更快,否则使用内联样式,不使用 StyleSheet.create
  • 进行任何动效或动画工作时,加载 expo-animation 技能——该技能负责决定是否使用动画、确定时长以及处理中断规则
  • 除非要创建胶囊形状,否则圆角使用 { borderCurve: 'continuous' }
  • 始终使用导航 Stack 标题,而非页面上的自定义文本元素
  • 为 ScrollView 添加内边距时,使用 contentContainerStyle 设置 padding 和 gap,而不是直接在 ScrollView 上设置 padding(可减少裁切)
  • 不支持 CSS 和 Tailwind——请使用内联样式

颜色

使用 expo-router 中的 Color API 获取原生语义颜色。它是 PlatformColor 的类型安全封装,通过 Color.ios.* 提供 iOS UIKit 颜色,通过 Color.android.material.*(静态)或 Color.android.dynamic.*(在 Android 12+ 上适配用户壁纸)提供 Android Material 3 颜色。这些颜色会在设备上解析,并自动适配浅色/深色模式和辅助功能设置,因此你不再需要维护单独的浅色/深色十六进制颜色表或 colors.web.ts 文件。

Color 具有平台特定性,因此请使用 Platform.select 包裹每个值,并为 Web 提供 default 十六进制颜色回退值。在 theme/colors.ts 中集中管理调色板,并在所有位置导入 colors:

// theme/colors.ts
import { Platform } from "react-native";
import { Color } from "expo-router";

export const colors = {
  label: Platform.select({
    ios: Color.ios.label,
    android: Color.android.dynamic.onSurface,
    default: "#000000",
  })!,
  secondaryLabel: Platform.select({
    ios: Color.ios.secondaryLabel,
    android: Color.android.dynamic.onSurfaceVariant,
    default: "#3c3c43",
  })!,
  separator: Platform.select({
    ios: Color.ios.separator,
    android: Color.android.dynamic.outlineVariant,
    default: "#c6c6c8",
  })!,
  systemBackground: Platform.select({
    ios: Color.ios.systemBackground,
    android: Color.android.dynamic.surface,
    default: "#ffffff",
  })!,
  secondarySystemBackground: Platform.select({
    ios: Color.ios.secondarySystemBackground,
    android: Color.android.dynamic.surfaceVariant,
    default: "#f2f2f7",
  })!,
  systemBlue: Platform.select({
    ios: Color.ios.systemBlue,
    android: Color.android.dynamic.primary,
    default: "#007aff",
  })!,
};
import { colors } from "@/theme/colors";

<View style={{ backgroundColor: colors.systemBackground }}>
  <Text style={{ color: colors.label }}>Title</Text>
</View>;
  • iOS 会在系统主题变化时自动重新解析这些颜色。在 Android 上,请在渲染这些颜色的任意组件中调用 useColorScheme(),以便主题切换时触发重新渲染(React Compiler 会记忆化组件时,这是必需的)。
  • 不要将 Color / PlatformColor 值传入 Reanimated 样式——它们是不透明的原生颜色对象,而非字符串;请在此类样式中使用静态颜色。
  • Platform.select({...})! 返回 string | OpaqueColorValue。大多数 React Native 样式属性接受 ColorValue(string | OpaqueColorValue),因此可以正常使用。但某些第三方属性只接受 string(例如 expo-image 中的 tintColor)。必要时进行类型转换:colors.label as string。

文本样式

  • 对所有显示重要数据或错误消息的 <Text/> 元素添加 selectable 属性
  • 计数器应使用 { fontVariant: 'tabular-nums' } 进行对齐

阴影

使用 CSS boxShadow 样式属性。切勿使用旧版 React Native 阴影或 elevation 样式。

<View style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }} />

支持 'inset' 阴影。

提交反馈

如果你在此技能中发现错误、误导性信息或过时信息,请进行反馈,以便 Expo 改进:

npx --yes @expo/agent-cli@latest feedback --category skills --subject "expo-native-ui" "<actionable feedback>"

仅在有具体且可操作的问题时提交。请尽可能提供相关背景信息。 如果 Agent 反复无法完成 Expo 任务,或用户不得不介入,请使用 --category evals 和相关 Expo 软件包或命令作为 --subject,简要报告任务、预期结果以及出现的问题。

评论

支持 Markdown