mcpField
B
building-ui

building-ui

github.com/gigs-slc设计与 UI379 次安装39 周前更新
代码仓库

关于 building-ui

building-ui 是面向 Expo Router 与 React Native 界面开发的技能指南,涵盖路由、原生控件、样式和运行方式。它通过一组专题参考资料和明确的库选择与实现规范,支持构建符合 iOS 界面惯例的应用。

主要功能

  1. 01Expo Router 路由组织规范
  2. 02原生控件与导航建议
  3. 03动画、媒体及存储参考
  4. 04样式与响应式布局规则
  5. 05Expo Go 与自定义构建指导

适用场景

  1. 01规划 Expo 应用的路由结构
  2. 02为界面选择 Expo 与 React Native 库
  3. 03实现适配屏幕和安全区域的布局
  4. 04判断是否需要自定义原生构建

安装

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

$npx skills add https://github.com/gigs-slc/react-native-skills --skill building-ui

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

包含的文件

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

references/
animations.md
controls.md
form-sheet.md
gradients.md
icons.md
media.md
route-structure.md
search.md
storage.md
tabs.md
visual-effects.md
webgpu-three.md

详细介绍

Expo UI 指南

参考资料

根据需要查阅以下资源:

  • ./references/route-structure.md -- 路由文件约定、动态路由、查询参数、路由组和文件夹组织方式
  • ./references/tabs.md -- 使用 NativeTabs 的原生标签栏、从 JS 标签栏迁移、iOS 26 功能
  • ./references/icons.md -- 使用 expo-symbols 的 SF Symbols、常用图标名称、动画和字重
  • ./references/controls.md -- 原生 iOS 控件:Switch、Slider、SegmentedControl、DateTimePicker、Picker
  • ./references/visual-effects.md -- 使用 expo-blur 实现模糊效果,以及使用 expo-glass-effect 实现液态玻璃效果
  • ./references/animations.md -- Reanimated 动画:进入、退出、布局、滚动驱动和手势
  • ./references/search.md -- 搜索栏与标题栏的集成、useSearch 钩子和筛选模式
  • ./references/gradients.md -- 使用 experimental_backgroundImage 实现 CSS 渐变(仅限新架构)
  • ./references/media.md -- Expo Router 的媒体处理,包括相机、音频、视频和文件保存
  • ./references/storage.md -- 数据存储模式,包括 SQLite、AsyncStorage 和 SecureStore
  • ./references/webgpu-three.md -- 使用 WebGPU 和 Three.js 实现 3D 图形、游戏和 GPU 驱动的可视化效果

运行应用

重要:始终先尝试使用 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 targets(通过 @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 使用路径别名;重构时优先使用别名而非相对导入。

路由

详细的路由约定请参见 ./references/route-structure.md。

  • 路由应放在 app 目录中。
  • 绝不要将组件、类型或工具与路由文件一起放在 app 目录中。这属于反模式。
  • 确保应用始终有一个与 "/" 匹配的路由,它可以位于路由组内。

库选择偏好

  • 绝不要使用 React Native 中已移除的模块,例如 Picker、WebView、SafeAreaView 或 AsyncStorage
  • 绝不要使用旧版 expo-permissions
  • 使用 expo-audio,而不是 expo-av
  • 使用 expo-video,而不是 expo-av
  • 使用 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 实现液态玻璃背景

响应性

  • 始终将根组件包裹在滚动视图中,以确保响应性
  • 使用 <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
  • 优先在 Stack.Screen 选项中使用 headerSearchBarOptions 添加搜索栏
  • 对包含可复制数据的文本使用 <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;请使用内联样式

文本样式

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

阴影

使用 CSS boxShadow 样式属性。绝不要使用旧版 React Native 阴影或 elevation 样式。

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

支持 'inset' 阴影。

导航

Link

使用 'expo-router' 中的 <Link href="/path" /> 在路由之间导航。

import { Link } from 'expo-router';

// Basic link
<Link href="/path" />

// Wrapping custom components
<Link href="/path" asChild>
  <Pressable>...</Pressable>
</Link>

尽可能添加 <Link.Preview>,遵循 iOS 规范。多使用上下文菜单和预览来增强导航体验。

Stack

  • 始终使用 _layout.tsx 文件定义堆栈
  • 使用 'expo-router/stack' 中的 Stack 创建原生导航堆栈
页面标题

在 Stack.Screen 选项中设置页面标题:

<Stack.Screen options={{ title: "Home" }} />

上下文菜单

为 Link 组件添加长按上下文菜单:

import { Link } from "expo-router";

<Link href="/settings" asChild>
  <Link.Trigger>
    <Pressable>
      <Card />
    </Pressable>
  </Link.Trigger>
  <Link.Menu>
    <Link.MenuAction
      title="Share"
      icon="square.and.arrow.up"
      onPress={handleSharePress}
    />
    <Link.MenuAction
      title="Block"
      icon="nosign"
      destructive
      onPress={handleBlockPress}
    />
    <Link.Menu title="More" icon="ellipsis">
      <Link.MenuAction title="Copy" icon="doc.on.doc" onPress={() => {}} />
      <Link.MenuAction
        title="Delete"
        icon="trash"
        destructive
        onPress={() => {}}
      />
    </Link.Menu>
  </Link.Menu>
</Link>;

链接预览

多使用链接预览来增强导航体验:

<Link href="/settings">
  <Link.Trigger>
    <Pressable>
      <Card />
    </Pressable>
  </Link.Trigger>
  <Link.Preview />
</Link>

链接预览可与上下文菜单搭配使用。

模态框

将屏幕作为模态框呈现:

<Stack.Screen name="modal" options={{ presentation: "modal" }} />

相比构建自定义模态框组件,优先使用此方式。

Sheet

将屏幕作为动态表单 Sheet 呈现:

<Stack.Screen
  name="sheet"
  options={{
    presentation: "formSheet",
    sheetGrabberVisible: true,
    sheetAllowedDetents: [0.5, 1.0],
    contentStyle: { backgroundColor: "transparent" },
  }}
/>
  • 使用 contentStyle: { backgroundColor: "transparent" } 可在 iOS 26+ 上让背景呈现 Liquid Glass 效果。

常见路由结构

在每个标签页中包含堆栈的标准应用布局:

app/
  _layout.tsx — <NativeTabs />
  (index,search)/
    _layout.tsx — <Stack />
    index.tsx — Main list
    search.tsx — Search view
// app/_layout.tsx
import { NativeTabs, Icon, Label } from "expo-router/unstable-native-tabs";
import { Theme } from "../components/theme";

export default function Layout() {
  return (
    <Theme>
      <NativeTabs>
        <NativeTabs.Trigger name="(index)">
          <Icon sf="list.dash" />
          <Label>Items</Label>
        </NativeTabs.Trigger>
        <NativeTabs.Trigger name="(search)" role="search" />
      </NativeTabs>
    </Theme>
  );
}

创建共享组路由,使两个标签页都能推送公共屏幕:

// app/(index,search)/_layout.tsx
import { Stack } from "expo-router/stack";
import { PlatformColor } from "react-native";

export default function Layout({ segment }) {
  const screen = segment.match(/\((.*)\)/)?.[1]!;
  const titles: Record<string, string> = { index: "Items", search: "Search" };

  return (
    <Stack
      screenOptions={{
        headerTransparent: true,
        headerShadowVisible: false,
        headerLargeTitleShadowVisible: false,
        headerLargeStyle: { backgroundColor: "transparent" },
        headerTitleStyle: { color: PlatformColor("label") },
        headerLargeTitle: true,
        headerBlurEffect: "none",
        headerBackButtonDisplayMode: "minimal",
      }}
    >
      <Stack.Screen name={screen} options={{ title: titles[screen] }} />
      <Stack.Screen name="i/[id]" options={{ headerLargeTitle: false }} />
    </Stack>
  );
}

评论

支持 Markdown