mcpField
B
building-native-ui

building-native-ui

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

关于 building-native-ui

building-native-ui 是面向 Expo 和 React Native 项目的界面构建指南,涵盖原生控件、样式、布局和交互。它提供参考资料与代码规范,并指导何时使用 Expo Go 或自定义构建。

主要功能

  1. 01原生控件与动画参考
  2. 02布局和响应式设计建议
  3. 03平台语义颜色用法
  4. 04样式与代码规范
  5. 05Expo Go 和自定义构建指引

适用场景

  1. 01为 Expo 路由构建界面
  2. 02实现原生控件与动画
  3. 03处理跨屏幕尺寸布局
  4. 04判断是否需要自定义原生构建

安装

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

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

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

包含的文件

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

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

详细介绍

Expo UI 指南

对于路由、链接、堆栈、标签页、模态框、底部面板和标题栏,请使用 expo-router 技能。

参考资料

按需查阅以下资源:

references/
  animations.md          Reanimated: entering, exiting, layout, scroll-driven, gestures
  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-image (sf: source), names, animations, weights
  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-* 软件包(相机、定位、通知等)
  • Expo Router 导航
  • 大多数 UI 库(reanimated、gesture handler 等)
  • 推送通知、深层链接等

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

代码风格

  • 注意避免字符串未终止。确保转义嵌套反引号;务必正确转义引号。
  • 始终在文件顶部使用 import 语句。
  • 文件名始终使用 kebab-case,例如 comment-card.tsx
  • 文件名中不要使用特殊字符
  • 配置 tsconfig.json 使用路径别名;重构时优先使用别名而非相对导入。

库的选择

  • 不要使用 React Native 中已移除的模块,例如 Picker、WebView、SafeAreaView 或 AsyncStorage
  • 不要使用旧版 expo-permissions
  • 使用 expo-audio,而不是 expo-av
  • 使用 expo-video,而不是 expo-av
  • 对于 SF Symbols,使用 source="sf:name" 的 expo-image,而不是 expo-symbols 或 @expo/vector-icons
  • 使用 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 contentInsetAdjustmentBehavior="automatic" />,而不是 <SafeAreaView>,以更智能地调整安全区域内边距
  • FlatList 和 SectionList 也应设置 contentInsetAdjustmentBehavior="automatic"
  • 使用 flexbox,而不是 Dimensions API
  • 测量屏幕尺寸时,始终优先使用 useWindowDimensions,而不是 Dimensions.get()

行为

  • 在 iOS 上有条件地使用 expo-haptics,打造更愉悦的体验
  • 使用内置触觉反馈的视图,例如 React Native 的 <Switch /> 和 @react-native-community/datetimepicker
  • 当路由属于一个 Stack 时,其第一个子组件几乎总应是一个设置了 contentInsetAdjustmentBehavior="automatic" 的 ScrollView
  • 向页面添加 ScrollView 时,它几乎总应是路由组件内的第一个组件
  • 对可能需要复制的数据文本,使用 <Text selectable /> 属性
  • 考虑对较大的数字进行格式化,例如 1.4M 或 38k
  • 除非在 webview 或 Expo DOM 组件中,否则不要使用 img 或 div 等内置元素

样式

遵循 Apple 人机界面指南。

通用样式规则

  • 优先使用 flex gap,而不是 margin 和 padding 样式
  • 尽可能优先使用 padding,而不是 margin
  • 始终考虑安全区域,可通过堆栈标题、标签页或 ScrollView/FlatList 的 contentInsetAdjustmentBehavior="automatic" 实现
  • 确保同时考虑顶部和底部安全区域内边距
  • 除非复用样式更快,否则使用内联样式,而非 StyleSheet.create
  • 为状态变化添加进入和退出动画
  • 除非要创建胶囊形状,否则圆角使用 { borderCurve: 'continuous' }
  • 始终使用导航堆栈标题,而不是页面上的自定义文本元素
  • 为 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 提供默认十六进制颜色回退值。在 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",
  })!,
  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 样式中——请在其中使用静态颜色(参见 references/animations.md)。
  • 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' 阴影。

评论

支持 Markdown