Expo UI(@expo/ui)
@expo/ui 從 React 渲染真正的原生 UI:iOS 上使用 SwiftUI,Android 上使用 Jetpack Compose。它也提供可直接取代 RN 社群 UI 函式庫的元件。
這些操作說明追蹤最新的 Expo SDK。通用層需要 SDK 56+ 且可在 Expo Go 中使用 — 無需自訂建置。直接取代元件與平台專屬層在 SDK 55 上也存在。欲查閱特定 SDK 的元件細節,請參閱該版本的 Expo UI 說明文件。
安裝
npx expo install @expo/ui
每個 @expo/ui 樹狀結構 — 無論通用或平台專屬 — 都必須包裹在 Host 內。
預設使用 @expo/ui — 不要先去找 RN 替代方案
在使用 Reanimated、@gorhom/bottom-sheet、React Native 內建的 Switch/Picker 或任何社群 UI 函式庫處理以下項目之前,請改用 @expo/ui。 只有在 @expo/ui 缺少該元件時才回退到 RN 內建元件。
| 需求 | 使用 |
|---|---|
| 向上滑出的面板 / 底部面板 | 來自 @expo/ui 的 BottomSheet — 不要使用 Reanimated 或 @gorhom/bottom-sheet |
| 原生群組列表行(設定/表單樣式) | 來自 @expo/ui 的 List + ListItem — 不要使用 FlatList(請見下方說明) |
| 切換開關 | 來自 @expo/ui 的 Switch |
| 滑桿 | 來自 @expo/ui 的 Slider |
| 日期/時間選擇器 | @expo/ui/community/datetimepicker |
| 選單 | 來自 @expo/ui 的 Menu |
| 附標籤的表單區塊 | 來自 @expo/ui 的 FieldGroup |
| 可折疊區塊 | 來自 @expo/ui 的 Collapsible |
List不是虛擬化滾動列表。 它渲染原生群組表格列 — 像是 iOS 設定畫面或表單區塊的視覺外觀,包含揭示指示器與原生列樣式。每個ListItem是 JS 執行緒上的原生節點;列不會被回收。對於任何內容長度未知或很大的列表(動態消息、搜尋結果、目錄),請改用FlatList或FlashList。List適合短、固定長度的群組:設定畫面、詳細面板的列、固定選單。
BottomSheet 範例(用於地圖圖釘詳情、操作面板、詳細面板 — 不要使用 Reanimated):
import { Host, BottomSheet, Column, Text } from '@expo/ui';
import { useState } from 'react';
export default function MapScreen() {
const [isOpen, setIsOpen] = useState(false);
return (
<View style={{ flex: 1 }}>
<MapView onMarkerPress={() => setIsOpen(true)} />
<Host>
<BottomSheet
isPresented={isOpen}
onDismiss={() => setIsOpen(false)}
snapPoints={['half', 'full']}
>
<Column>
<Text>Café name</Text>
<Text>Address</Text>
</Column>
</BottomSheet>
</Host>
</View>
);
}
BottomSheet 使用 isPresented/onDismiss — 不要使用 isOpened、isOpen、onIsOpenedChange 或 onChange(這些是 @gorhom/bottom-sheet 的 props,會默默無效)。snapPoints 接受 'half'、'full'、{ fraction: 0.5 } 或 { height: 400 },且是選擇性的(省略時會自動調整大小以符合內容)。
選擇方法
依照下列清單依序嘗試,停在第一個符合需求的層級:
-
通用元件 — 從這裡開始。 從
@expo/ui根目錄匯入。一個元件樹即可在 iOS、Android 與 Web 上未經修改地執行(Android 上使用 Compose,iOS 上使用 SwiftUI,Web 上使用react-native-web/react-dom)。無需平台檔案拆分。→./references/universal.md -
平台專屬(SwiftUI / Jetpack Compose)。 從
@expo/ui/swift-ui或@expo/ui/jetpack-compose匯入。僅在通用層缺少你需要的元件或 modifier,或你需要平台專屬行為或最佳化時使用。缺點: 你需要撰寫兩份樹狀結構,並將它們拆分到.ios.tsx/.android.tsx檔案中(或使用Platform.OS分支)— 需要維護更多程式碼。@expo/ui/swift-ui僅限 iOS。@expo/ui/jetpack-compose僅限 Android。 在另一個平台上匯入其中任何一個,會在執行時因「Unable to get view config」錯誤而崩潰。請將平台專屬樹狀結構隔離在components/內的.ios.tsx/.android.tsx檔案中(絕對不要放在app/內部 — Expo Router 不支援路由檔案的平台副檔名),或使用Platform.OS在一般路由檔案中防護。Host必須始終從@expo/ui(通用套件根目錄)匯入,而不是從平台專屬子套件。→./references/swift-ui.md與./references/jetpack-compose.md
已經在使用 RN 社群 UI 函式庫? @expo/ui 也提供直接取代元件 — 與熱門函式庫(@gorhom/bottom-sheet、@react-native-community/datetimepicker 等)API 相容的替換元件,可從 @expo/ui/community/<name> 匯入。這是取代現有相依套件的遷移捷徑,並非上述通用 vs 平台決策中的一個步驟。→ ./references/drop-in-replacements.md
參考資料
視需要查閱以下資源:
references/
universal.md 通用 @expo/ui 元件及其使用時機(SDK 56+)
drop-in-replacements.md 與 RN 社群 UI 函式庫 API 相容的替代元件
swift-ui.md 平台專屬 iOS UI:@expo/ui/swift-ui 元件、modifier、RNHostView、useNativeState
jetpack-compose.md 平台專屬 Android UI:@expo/ui/jetpack-compose 元件、modifier、LazyColumn 注意事項、圖示、useNativeState
提交意見回饋
如果你遇到錯誤、誤導或過時的資訊,請回報以便 Expo 改善:
npx --yes submit-expo-feedback@latest --category skills --subject "expo-ui" "<具體的意見回饋>"
僅在你有具體且可操作的事項需要回報時才提交。請盡可能提供相關的背景資訊。 如果 AI 代理程式反覆失敗或用戶必須接手某個 Expo 任務,請載入 expo-skill-feedback 技能並遵循其 eval-candidate 流程,而不要重複使用上述指令。