用 expo-native-ui 让 AI 写出更像原生 App 的 Expo 界面

前言

用 Cursor、Claude Code 这类 AI 编程工具写 Expo / React Native 界面时,常见情况是:功能能跑,但观感像「套了一层 Web」——颜色写死成 hex、阴影还在用旧的 shadow* / elevation、安全区靠猜、动画随便上一套 Animated。模型并不缺组件名,缺的是一套和当前 Expo SDK 对齐的原生 UI 约定。

Expo 官方把这类约定收成了 Agent Skill。其中 expo-native-ui 专门管「屏幕长什么样」:语义色、原生控件、SF Symbols、动画、模糊与渐变、本地存储与响应式布局。路由、Tabs、Modal 等导航则交给同仓库里的 expo-router Skill。官方文档给出的典型提示是:「Build a settings screen with native-feeling controls」,代理会自动匹配到 expo-native-ui

本文基于 Expo 官方仓库 expo/skillsexpo-native-uiSKILL.md(版本 1.1.1,MIT)以及 docs.expo.dev/skills 的安装说明整理,说明它是什么、装在哪里、以及让 AI 按这套规范写界面时要注意什么。

这是什么

expo-native-ui 是 Expo 团队维护的 Framework(开源) 类 Skill,属于 expo/skills 插件里的免费 SDK 技能之一。它不是一个 npm UI 库,而是一份给 AI Agent 读的结构化说明(SKILL.md + references/),告诉代理在 Expo 项目里如何搭出「原生感」更强的屏幕。

官方描述可以概括为:按 Apple Human Interface Guidelines 做样式;用语义色、原生控件、SF Symbols、媒体、动画、视觉效果、渐变、存储和响应式布局,构建观感接近系统 App 的 Expo 界面。导航相关需求应改用 expo-router Skill。

Skill 目录下还挂了若干按需查阅的参考文档,例如:

references/
  animations.md      Reanimated:进入/退出、布局、滚动驱动、手势
  controls.md        原生控件:Switch、Slider、SegmentedControl、DateTimePicker、Picker
  gradients.md       CSS 渐变(experimental_backgroundImage,需 New Architecture)
  icons.md           通过 expo-image 的 sf: 源使用 SF Symbols
  media.md           相机、音频、视频与文件保存
  storage.md         SQLite、AsyncStorage、SecureStore
  visual-effects.md  模糊(expo-blur)与 liquid glass(expo-glass-effect)
  webgpu-three.md    WebGPU / Three.js 三维与 GPU 可视化

核心约定与亮点

下面这些点都直接写在官方 SKILL.md 里,也是它和「随便让 AI 写 RN」差别最大的地方。

1、先用 Expo Go,再考虑自定义构建

Skill 把这一点标成 CRITICAL:多数 Expo 应用不需要自定义原生代码。流程是先 npx expo start,用 Expo Go 扫码验证;只有本地 Expo Module、Apple Targets(如 widget / App Clip)、Expo Go 未收录的第三方原生模块,或 app.json 表达不了的原生配置,才需要 npx expo run:ios/androideas build

这能减少 AI 一上来就跑本地原生构建、拖慢迭代的情况。

2、库与 API 偏好(避免过时写法)

Skill 明确要求代理遵守一批「用这个、别用那个」:

  • 不要用已从 React Native 移除的模块(如旧版 Picker、WebView、SafeAreaView、AsyncStorage 等内置用法)
  • 不要用已废弃的 expo-permissions
  • 音视频用 expo-audio / expo-video,不要再用 expo-av
  • SF Symbols 用 expo-imagesource="sf:name",不要用 expo-symbols@expo/vector-icons 凑合
  • 安全区用 react-native-safe-area-context,不用 RN 内置 SafeAreaView
  • 平台判断优先 process.env.EXPO_OS,而不是 Platform.OS
  • 语义色用 expo-routerColor API,而不是手写 PlatformColor
  • SDK 56+ 不要直接从 @react-navigation/* 导入,改走 expo-router/react-navigation

样式侧还要求:跟 Apple HIG;优先 flex gap;圆角用 { borderCurve: 'continuous' };阴影用 CSS 风格的 boxShadow,不要再用旧的 shadow / elevation;不支持 CSS / Tailwind(需要 Tailwind 时应走单独的 expo-tailwind-setup Skill)。

3、语义色:一套可随系统明暗变化的 palette

官方示例把颜色集中在 theme/colors.ts,用 Color(来自 expo-router)包一层 Platform.select,并为 Web 提供 default 十六进制回退:

// 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",
  })!,
  systemBackground: Platform.select({
    ios: Color.ios.systemBackground,
    android: Color.android.dynamic.surface,
    default: "#ffffff",
  })!,
  systemBlue: Platform.select({
    ios: Color.ios.systemBlue,
    android: Color.android.dynamic.primary,
    default: "#007aff",
  })!,
};

页面里直接引用 colors.labelcolors.systemBackground 即可。注意:不要把 Color / PlatformColor 传进 Reanimated 样式,动画里要用静态颜色(references/animations.md 也写了这一点)。

4、动画默认走 Reanimated

references/animations.md 要求使用 Reanimated v4,避免 React Native 内置 Animated。进入/退出可用 FadeIn / FadeOut,布局变化可用 LinearTransition

import Animated, {
  FadeIn,
  FadeOut,
  LinearTransition,
} from "react-native-reanimated";

function App() {
  return (
    <Animated.View
      entering={FadeIn}
      exiting={FadeOut}
      layout={LinearTransition}
    />
  );
}

同文件还覆盖滚动驱动动画、手势拖拽、键盘高度联动、列表错峰进入等模式,并建议交互动画尽量控制在 300ms 内、优先用 transform 而不是改宽高。

5、原生控件与触感

references/controls.md 偏向系统控件:SwitchSegmentedControlSliderDateTimePickerPicker 等。Switch、DateTimePicker 自带 haptics,Skill 提醒不要再叠一层多余震动;分段控件最多约 4 项、文案尽量短,颜色尽量别乱改,好让暗色模式跟着系统走。

安装与启用

expo-native-ui 随整个 Expo Skills 套件分发。安装方式按 AI 工具区分(官方 README 与 docs.expo.dev/skills 一致)。

Claude Code

从官方插件市场安装 Expo 插件:

claude plugin install expo@claude-plugins-official

也可以在 Claude Code 里执行:

/plugin install expo@claude-plugins-official

Codex

codex plugin add expo@openai-curated

或在 Codex 中打开 /plugins,从 OpenAI-curated marketplace 安装 expo

Cursor 及其他 Agent

若尚未安装,在项目根目录用 skills CLI

# npm
npx skills add expo/skills

# yarn
yarn dlx skills add expo/skills

# pnpm
pnpm dlx skills add expo/skills

# bun
bunx skills add expo/skills

仓库 README 也给出等价写法,可一次装入全部 Expo Skills,并可选指定单个 Skill:

npx skills@latest add expo/skills --skill '*'

只装本篇相关 Skill 时,可把 --skill 换成 expo-native-ui(CLI 仍可能询问安装到哪个 Agent)。装完后重启或刷新 Agent 会话,让它重新发现 SKILL.md

Cursor 侧:打开 Settings → Rules, Skills, Subagents,确认 Include third-party Plugins, Skills, and other configs 已开启,在 Skills 列表里能看到 Expo Skills。官方说明:Cursor 的 Skills 不会出现在 / 斜杠菜单里,而是在你提 Expo 相关需求时由代理自动匹配。

更新(skills CLI 安装路径):

npx skills@latest update

或更新单个 Skill,例如:

npx skills@latest update expo-router

Claude Code / Codex 的插件安装则走各自 marketplace 的更新机制。

典型用法

安装后不必手动「调用」某个命令;用自然语言描述界面需求即可。官方文档列出的示例提示:

Build a settings screen with native-feeling controls

README 里还有更贴近整屏搭建的说法:

Build a native-feeling Expo Router screen with tabs, modals, and animations.

后一种往往会同时触发 expo-router(导航结构)和 expo-native-ui(样式、控件、动画)。实际协作时可以写得更具体,例如:

用 Expo Router 做一个设置页:分组开关、分段控件、日期选择;
颜色走 expo-router 的 Color 语义色;开关用系统 Switch;
列表项进入用 Reanimated FadeIn;先在 Expo Go 里验证,不要一上来自定义原生构建。

代理按 Skill 工作时,通常会:优先 Expo Go;用语义色与 boxShadow;控件选原生组件;动画走 Reanimated;文件名用 kebab-case(如 comment-card.tsx);路由标题用导航栈 title,而不是页面里再手写一个大标题。

适用场景与注意事项

比较适合:

  • 用 AI 在 Expo 项目里搭设置页、列表页、详情页等「系统感」界面
  • 希望输出统一遵守 HIG、语义色、安全区、Reanimated 等约定,减少过时 API
  • 已装或准备装 expo-router,需要把「导航」和「视觉/交互」分工给不同 Skill

需要注意:

  • 它教的是 Agent 怎么写 Expo UI,不是替代 Expo 文档 / Expo CLI / EAS CLI;源码与命令仍以官方文档为准
  • expo-ui 不同:后者面向 @expo/ui(SwiftUI / Jetpack Compose 那一套);expo-native-ui 更偏 React Native 组件 + Expo SDK 的原生观感约定
  • CSS / Tailwind 不在本 Skill 范围内;需要 Tailwind v4 / NativeWind v5 时用 expo-tailwind-setup
  • 渐变参考里提到的 experimental_backgroundImage 依赖 New Architecture,项目架构不匹配时不要强行照抄
  • 发现 Skill 内容过时或误导时,官方提供反馈命令(需具体、可操作):
npx --yes submit-expo-feedback@latest --category skills --subject "expo-native-ui" "<actionable feedback>"

小结

expo-native-ui 把「怎样写出更像原生的 Expo 屏幕」写成可被 Cursor、Claude Code、Codex 等 Agent 自动加载的 Skill:语义色、原生控件、Reanimated、安全区与阴影约定、以及先 Expo Go 后自定义构建的流程,都写在官方 SKILL.mdreferences/ 里。装上 Expo Skills 之后,用一句「做有原生感的设置页」往往就能对上这套规范。

官方地址:

  • Skill 目录:https://github.com/expo/skills/tree/main/plugins/expo/skills/expo-native-ui
  • 仓库总览:https://github.com/expo/skills
  • 安装与技能列表:https://docs.expo.dev/skills
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜