AgentSkillsCN

ios-native-expert

强制要求:严格遵守 iOS 26 的原生设计规范,包括液态玻璃效果、所有系统颜色的 PlatformColor 支持、通过 useTheme()/useThemeColors() 实现集中化主题管理、SF Symbols 图标集、触觉反馈、所有滚动视图的 contentInsetAdjustmentBehavior 设置,以及原生导航标题栏。每当您在 /mobile 目录下修改任何文件时,都必须使用此技能。每个 iOS 组件都必须完全合规——一旦发现违规,必须立即上报并予以修复。切勿对 Web 代码或仅适用于 Android 的实现进行任何修改。相关文档:docs/IOS_26_IMPLEMENTATION_GUIDE.md

SKILL.md
--- frontmatter
name: ios-native-expert
description: "MANDATORY: Enforces iOS 26 native design compliance including Liquid Glass, PlatformColor for all system colors, centralized theming via useTheme()/useThemeColors(), SF Symbols, haptic feedback, contentInsetAdjustmentBehavior on all scroll views, and native navigation headers. Use this skill whenever touching any file in /mobile. Every iOS component MUST comply -- violations MUST be reported and fixed immediately. NEVER modifies web code or Android-only implementations. Reference docs: docs/IOS_26_IMPLEMENTATION_GUIDE.md"

iOS Native Expert -- MANDATORY COMPLIANCE

Your job: Enforce total iOS 26 native design compliance across the entire mobile app. These rules are NOT optional. They are REQUIRED for every component, every screen, every PR.

If you identify ANY component or page that violates these rules, you are RESPONSIBLE for reporting it and fixing it.


REFERENCE DOCUMENTATION

Before making changes, search and read these files for detailed patterns and API references:

DocumentPathContains
Implementation Guidedocs/IOS_26_IMPLEMENTATION_GUIDE.mdComplete component-by-component patterns, library decisions, migration checklist, known issues
API Reference.cursor/skills/ios-native-expert/reference.mdQuick-reference for PlatformColor names, expo-glass-effect API, expo-symbols API, haptics API, spring presets, HIG sizing
Design Researchdocs/IOS_26_DESIGN_RESEARCH.mdLiquid Glass design properties, visual tokens, community-derived values
Native Researchdocs/IOS_26_NATIVE_RESEARCH.mdUI patterns research, library comparisons, common patterns

When in doubt, search these docs first. Run: Search for "GlassView" in docs/IOS_26_IMPLEMENTATION_GUIDE.md


MANDATORY RULES -- ZERO EXCEPTIONS

Rule 1: NO Hardcoded Hex Colors for System UI

Every background, text color, separator, and fill that corresponds to a system semantic color MUST use PlatformColor() on iOS or useThemeColors() from context.

tsx
// VIOLATION -- hardcoded colors don't adapt to light/dark/glass/high-contrast
backgroundColor: '#FFFFFF'
color: '#000000'
borderColor: '#E5E5EA'
backgroundColor: isDark ? '#1C1C1E' : '#FFFFFF'

// CORRECT -- use PlatformColor on iOS, theme colors on Android
backgroundColor: Platform.OS === 'ios'
  ? PlatformColor('systemBackground')
  : colors.background
color: Platform.OS === 'ios'
  ? PlatformColor('label')
  : colors.onSurface
borderColor: Platform.OS === 'ios'
  ? PlatformColor('separator')
  : colors.outline

The ONLY exceptions are brand colors (#B06D1E, #FFBA70, #E91E63, #FFFAF2) which should use DynamicColorIOS for light/dark adaptation.

Color mapping reference:

HardcodedReplace With
#FFFFFF, whitePlatformColor('systemBackground')
#F2F2F7, #F5F5F5, #FAFAFAPlatformColor('secondarySystemBackground')
#000000, #333333, #1A1A1APlatformColor('label')
#666666, #8E8E93, #6B7280PlatformColor('secondaryLabel')
#9CA3AF, #AEAEB2PlatformColor('tertiaryLabel')
#E5E5EA, #D1D1D6, #E0E0E0PlatformColor('separator')
#C6C6C8, #38383APlatformColor('opaqueSeparator')
#1C1C1E, #2C2C2EPlatformColor('secondarySystemBackground') or PlatformColor('tertiarySystemBackground')
#3A3A3CPlatformColor('systemGray4')
#007AFFPlatformColor('systemBlue')
#FF3B30PlatformColor('systemRed')
#34C759PlatformColor('systemGreen')
#FF9500PlatformColor('systemOrange')
#FF2D55PlatformColor('systemPink')

Rule 2: NO useColorScheme() in Individual Components

useColorScheme() is called ONCE at the root in ThemeProvider. Every other component MUST use:

  • useTheme() -- full theme object
  • useThemeColors() -- just colors
  • useIsDarkMode() -- just boolean
tsx
// VIOLATION
import { useColorScheme } from 'react-native';
const colorScheme = useColorScheme();
const isDark = colorScheme === 'dark';

// CORRECT
import { useThemeColors, useIsDarkMode } from '@/context/ThemeContext';
const colors = useThemeColors();
const isDark = useIsDarkMode();

Allowed exceptions: _layout.tsx (root), ThemeContext.tsx, platformColors.ts.

Rule 3: Liquid Glass on ALL Floating Elements

Every floating/overlay element on iOS 26 MUST use Liquid Glass. Use the existing LiquidGlassView wrapper component or GlassView directly.

Where Liquid Glass is REQUIRED:

  • Tab bars (automatic via NativeTabs)
  • Navigation headers (automatic via headerBlurEffect)
  • Floating action bars / buttons
  • Bottom sheets / sheet headers
  • Context menus (automatic via native context menu)
  • Alerts (automatic via Alert.alert)
  • Action sheets (automatic via ActionSheetIOS)
  • Custom floating overlays, toolbars, and pill controls
  • Segmented controls (automatic via native component)

Where Liquid Glass is NOT used:

  • List cells / table rows
  • Card content backgrounds
  • Full-page content areas
  • Text containers
  • Media content

Implementation pattern:

tsx
import { LiquidGlassView } from '@/components/ui/LiquidGlass';

<LiquidGlassView
  style={styles.floatingBar}
  fallbackColor={colors.surface}
  isInteractive={true}
  glassEffectStyle="regular"
>
  {/* floating content */}
</LiquidGlassView>

Never use BlurView alone for floating elements. Always use LiquidGlassView (which falls back to solid background) or check isGlassEffectAPIAvailable() and use GlassView directly.

Rule 4: contentInsetAdjustmentBehavior="automatic" on ALL Scroll Views

Every ScrollView, FlatList, and SectionList MUST set this prop. It ensures content insets adjust for translucent headers and tab bars on iOS.

tsx
// VIOLATION
<ScrollView>

// CORRECT
<ScrollView contentInsetAdjustmentBehavior="automatic">
<FlatList contentInsetAdjustmentBehavior="automatic" />
<SectionList contentInsetAdjustmentBehavior="automatic" />

Rule 5: Haptic Feedback on ALL Interactive Elements

Every Pressable, TouchableOpacity, and button-like element MUST include haptic feedback on iOS.

tsx
import * as Haptics from 'expo-haptics';

<Pressable onPress={() => {
  Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
  handleAction();
}}>
ActionHaptic
Tab selectionselectionAsync()
Button tapimpactAsync(ImpactFeedbackStyle.Light)
Card pressimpactAsync(ImpactFeedbackStyle.Medium)
Toggle switchimpactAsync(ImpactFeedbackStyle.Rigid)
Long press triggerimpactAsync(ImpactFeedbackStyle.Heavy)
Match / successnotificationAsync(NotificationFeedbackType.Success)
ErrornotificationAsync(NotificationFeedbackType.Error)

Rule 6: Native Navigation Headers -- No Custom Headers

Use the native Stack.Screen header with headerBlurEffect and headerLargeTitle. Do NOT build custom View-based headers unless the screen requires a complex custom header (e.g., image header, media overlay).

tsx
// VIOLATION -- custom View-based header for a standard list screen
<View style={styles.header}>
  <TouchableOpacity onPress={goBack}><Text>Back</Text></TouchableOpacity>
  <Text style={styles.title}>Settings</Text>
</View>

// CORRECT -- native header
<Stack.Screen options={{
  title: 'Settings',
  headerLargeTitle: Platform.OS === 'ios',
  headerBlurEffect: Platform.OS === 'ios' ? 'systemMaterial' : undefined,
}} />

Rule 7: SF Symbols for ALL iOS Icons

All icons on iOS MUST use expo-symbols SymbolView or the PlatformIcon abstraction. Never use Ionicons, MaterialIcons, or FontAwesome on iOS.

tsx
import { SymbolView } from 'expo-symbols';

<SymbolView
  name="heart.fill"
  tintColor={PlatformColor('systemPink')}
  style={{ width: 24, height: 24 }}
  type="hierarchical"
/>

Rule 8: NativeTabs with iOS 26 Features

The tab bar MUST use NativeTabs (already implemented). Ensure these iOS 26 features are enabled:

  • minimizeBehavior="onScrollDown" -- auto-minimize on scroll
  • SF Symbol icons with default/selected states via sf prop

Rule 9: Native Sheets and Modals

Prefer expo-router formSheet presentation or @gorhom/bottom-sheet for bottom sheets. When using @gorhom/bottom-sheet, add a glass background:

tsx
import { LiquidGlassView } from '@/components/ui/LiquidGlass';

<BottomSheet
  backgroundComponent={({ style }) => (
    <LiquidGlassView style={style} glassEffectStyle="regular" />
  )}
/>

Rule 10: DynamicColorIOS for Brand Colors

Custom brand colors that need light/dark adaptation MUST use DynamicColorIOS:

tsx
import { DynamicColorIOS, Platform } from 'react-native';

const brandPrimary = Platform.OS === 'ios'
  ? DynamicColorIOS({ light: '#B06D1E', dark: '#FFBA70' })
  : isDark ? '#FFBA70' : '#B06D1E';

SCOPE: iOS-ONLY

ActionAllowed
Modify /mobile iOS-specific codeYES
Use Platform.OS === 'ios' conditionalsYES
Add iOS-only featuresYES
Modify /web in any wayNEVER
Break Android functionalityNEVER
Remove Android code pathsNEVER

When adding iOS-specific behavior, always provide Android fallbacks:

tsx
// Pattern: iOS-specific with Android fallback
backgroundColor: Platform.OS === 'ios'
  ? PlatformColor('systemBackground')
  : colors.background,

EXISTING COMPONENTS TO USE

ComponentLocationUse For
LiquidGlassViewcomponents/ui/LiquidGlass.tsxGlass cards, floating elements
LiquidGlassHeadercomponents/ui/LiquidGlass.tsxCustom header backgrounds
LiquidGlassFABcomponents/ui/LiquidGlass.tsxFloating action buttons
useLiquidGlass()components/ui/LiquidGlass.tsxCheck glass availability
PlatformIconcomponents/ui/PlatformIcon.tsxCross-platform icons (SF Symbols on iOS)
ScreenHeadercomponents/ui/ScreenHeader.tsxCustom screen headers (has liquidGlass prop)
useTheme()context/ThemeContext.tsxFull theme with dark mode
useThemeColors()context/ThemeContext.tsxJust color values
useIsDarkMode()context/ThemeContext.tsxJust boolean
useSemanticColors()utils/platformColors.tsPlatformColor-based semantic colors

PRE-COMPLETION CHECKLIST

Before submitting ANY change to a mobile component:

  • No hardcoded hex colors for system UI elements (backgrounds, text, borders, separators)
  • PlatformColor used for all iOS system colors
  • useTheme()/useThemeColors() used instead of useColorScheme() for theme access
  • contentInsetAdjustmentBehavior="automatic" on all ScrollView/FlatList/SectionList
  • Haptic feedback on all interactive elements (Pressable, TouchableOpacity, buttons)
  • SF Symbols via SymbolView or PlatformIcon for all iOS icons
  • Liquid Glass on floating elements (LiquidGlassView, GlassView, or native component)
  • Native navigation used instead of custom View-based headers (where possible)
  • Platform.OS === 'ios' isolates all iOS-specific code
  • Android unchanged -- all iOS changes use Platform checks
  • Web untouched -- no changes to /web directory

DOCUMENTATION LINKS