首页/移动开发/building-native-ui
B

building-native-ui

by @expov1.0.0
4.3(0)

针对Expo项目构建原生UI的AI代理技能集,提供智能辅助,帮助移动开发者高效设计和实现跨平台用户界面。

React NativeExpoNative UI ComponentsMobile DevelopmentiOS DevelopmentAndroid DevelopmentGitHub
安装方式
npx skills add expo/skills --skill building-native-ui
compare_arrows

Before / After 效果对比

1
使用前

手动编写原生UI代码复杂,耗时且易出错。难以快速实现跨平台一致性,影响移动应用开发效率。

使用后

智能辅助原生UI构建,自动生成高质量代码。显著提升开发效率,确保UI一致性,加速移动应用发布。

description SKILL.md

building-native-ui

Expo UI Guidelines

References

Consult these resources as needed:

references/
  animations.md          Reanimated: entering, exiting, layout, scroll-driven, gestures
  controls.md            Native iOS: Switch, Slider, SegmentedControl, DateTimePicker, Picker
  form-sheet.md          Form sheets in expo-router: configuration, footers and background interaction. 
  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
  route-structure.md     Route conventions, dynamic routes, groups, folder organization
  search.md              Search bar with headers, useSearch hook, filtering patterns
  storage.md             SQLite, AsyncStorage, SecureStore
  tabs.md                NativeTabs, migration from JS tabs, iOS 26 features
  toolbar-and-headers.md Stack headers and toolbar buttons, menus, search (iOS only)
  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
  zoom-transitions.md    Apple Zoom: fluid zoom transitions with Link.AppleZoom (iOS 18+)

Running the App

CRITICAL: Always try Expo Go first before creating custom builds.

Most Expo apps work in Expo Go without any custom native code. Before running npx expo run:ios or npx expo run:android:

  • Start with Expo Go: Run npx expo start and scan the QR code with Expo Go

  • Check if features work: Test your app thoroughly in Expo Go

  • Only create custom builds when required - see below

When Custom Builds Are Required

You need npx expo run:ios/android or eas build ONLY when using:

  • Local Expo modules (custom native code in modules/)

  • Apple targets (widgets, app clips, extensions via @bacons/apple-targets)

  • Third-party native modules not included in Expo Go

  • Custom native configuration that can't be expressed in app.json

When Expo Go Works

Expo Go supports a huge range of features out of the box:

  • All expo-* packages (camera, location, notifications, etc.)

  • Expo Router navigation

  • Most UI libraries (reanimated, gesture handler, etc.)

  • Push notifications, deep links, and more

If you're unsure, try Expo Go first. Creating custom builds adds complexity, slower iteration, and requires Xcode/Android Studio setup.

Code Style

  • Be cautious of unterminated strings. Ensure nested backticks are escaped; never forget to escape quotes correctly.

  • Always use import statements at the top of the file.

  • Always use kebab-case for file names, e.g. comment-card.tsx

  • Always remove old route files when moving or restructuring navigation

  • Never use special characters in file names

  • Configure tsconfig.json with path aliases, and prefer aliases over relative imports for refactors.

Routes

See ./references/route-structure.md for detailed route conventions.

  • Routes belong in the app directory.

  • Never co-locate components, types, or utilities in the app directory. This is an anti-pattern.

  • Ensure the app always has a route that matches "/", it may be inside a group route.

Library Preferences

  • Never use modules removed from React Native such as Picker, WebView, SafeAreaView, or AsyncStorage

  • Never use legacy expo-permissions

  • expo-audio not expo-av

  • expo-video not expo-av

  • expo-image with source="sf:name" for SF Symbols, not expo-symbols or @expo/vector-icons

  • react-native-safe-area-context not react-native SafeAreaView

  • process.env.EXPO_OS not Platform.OS

  • React.use not React.useContext

  • expo-image Image component instead of intrinsic element img

  • expo-glass-effect for liquid glass backdrops

Responsiveness

  • Always wrap root component in a scroll view for responsiveness

  • Use <ScrollView contentInsetAdjustmentBehavior="automatic" /> instead of <SafeAreaView> for smarter safe area insets

  • contentInsetAdjustmentBehavior="automatic" should be applied to FlatList and SectionList as well

  • Use flexbox instead of Dimensions API

  • ALWAYS prefer useWindowDimensions over Dimensions.get() to measure screen size

Behavior

  • Use expo-haptics conditionally on iOS to make more delightful experiences

  • Use views with built-in haptics like <Switch /> from React Native and @react-native-community/datetimepicker

  • When a route belongs to a Stack, its first child should almost always be a ScrollView with contentInsetAdjustmentBehavior="automatic" set

  • When adding a ScrollView to the page it should almost always be the first component inside the route component

  • Prefer headerSearchBarOptions in Stack.Screen options to add a search bar

  • Use the <Text selectable /> prop on text containing data that could be copied

  • Consider formatting large numbers like 1.4M or 38k

  • Never use intrinsic elements like 'img' or 'div' unless in a webview or Expo DOM component

Styling

Follow Apple Human Interface Guidelines.

General Styling Rules

  • Prefer flex gap over margin and padding styles

  • Prefer padding over margin where possible

  • Always account for safe area, either with stack headers, tabs, or ScrollView/FlatList contentInsetAdjustmentBehavior="automatic"

  • Ensure both top and bottom safe area insets are accounted for

  • Inline styles not StyleSheet.create unless reusing styles is faster

  • Add entering and exiting animations for state changes

  • Use { borderCurve: 'continuous' } for rounded corners unless creating a capsule shape

  • ALWAYS use a navigation stack title instead of a custom text element on the page

  • When padding a ScrollView, use contentContainerStyle padding and gap instead of padding on the ScrollView itself (reduces clipping)

  • CSS and Tailwind are not supported - use inline styles

Text Styling

  • Add the selectable prop to every <Text/> element displaying important data or error messages

  • Counters should use { fontVariant: 'tabular-nums' } for alignment

Shadows

Use CSS boxShadow style prop. NEVER use legacy React Native shadow or elevation styles.

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

'inset' shadows are supported.

Navigation

Link

Use <Link href="/path" /> from 'expo-router' for navigation between routes.

import { Link } from 'expo-router';

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

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

Whenever possible, include a <Link.Preview> to follow iOS conventions. Add context menus and previews frequently to enhance navigation.

Stack

  • ALWAYS use _layout.tsx files to define stacks

  • Use Stack from 'expo-router/stack' for native navigation stacks

Page Title

Set the page title in Stack.Screen options:

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

Context Menus

Add long press context menus to Link components:

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 Previews

Use link previews frequently to enhance navigation:

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

Link preview can be used with context menus.

Modal

Present a screen as a modal:

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

Prefer this to building a custom modal component.

Sheet

Present a screen as a dynamic form sheet:

<Stack.Screen
  name="sheet"
  options={{
    presentation: "formSheet",
    sheetGrabberVisible: true,
    sheetAllowedDetents: [0.5, 1.0],
    contentStyle: { backgroundColor: "transparent" },
  }}
/>

  • Using contentStyle: { backgroundColor: "transparent" } makes the background liquid glass on iOS 26+.

Common route structure

A standard app layout with tabs and stacks inside each tab:

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>
  );
}

Create a shared group route so both tabs can push common screens:

// 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>
  );
}

Weekly Installs19.0KRepositoryexpo/skillsGitHub Stars1.5KFirst SeenJan 19, 2026Security AuditsGen Agent Trust HubPassSocketPassSnykPassInstalled onopencode14.4Kcodex13.8Kgemini-cli13.7Kgithub-copilot13.4Kcursor12.9Kclaude-code11.3K

forum用户评价 (0)

发表评价

效果
易用性
文档
兼容性

暂无评价,来写第一条吧

统计数据

安装量18.9K
评分4.3 / 5.0
版本1.0.0
更新日期2026年3月17日
对比案例1 组

用户评分

4.3(0)
5
0%
4
0%
3
0%
2
0%
1
0%

为此 Skill 评分

0.0

兼容平台

🔧Claude Code
🔧OpenClaw
🔧OpenCode
🔧Codex
🔧Gemini CLI
🔧GitHub Copilot
🔧Amp
🔧Kimi CLI

时间线

创建2026年3月17日
最后更新2026年3月17日