UI 组件
Core/UI 基础组件、Toast 与触感反馈。
Core/UI/ 是应用的组件库——带品牌样式、可复用的 SwiftUI 视图,每个功能都由它们组合
而成,从而让各屏幕保持一致,重塑样式也只需一处改动。本页盘点这些组件,指引你到能渲染
每个组件的实时画廊,并覆盖两套全应用级反馈系统(Toast 与触感)。它们全都消费
主题令牌。
实时画廊
看全貌最快的方式是运行中应用里的 Component 标签页:ComponentGalleryView 直接
从 ComponentCatalog 渲染,点按一行会推入该组件的可交互演示(ComponentDetailView)。
它是参考实现——并且与应用其余部分不同,它按设计仅为英文(文案是目录里的纯字符串,
而非 Localizable.xcstrings)。
画廊完全离线可用、无需任何密钥——它属于安装中"组件画廊 标签页离线可用"的检查项。
组件清单
按画廊相同的方式分组(ComponentGroup):
控件(Controls)
| 组件 | 是什么 |
|---|---|
AppButton | 带品牌样式的按钮,4 种变体(primary / secondary / destructive / text),含 isLoading / isDisabled / 可选图标 / fullWidth。 |
ThemeToggle | 绑定到 ThemeController 的分段 Picker(系统 / 浅色 / 深色)。 |
输入(Inputs)
| 组件 | 是什么 |
|---|---|
AppTextField | 带前置图标、密文输入、内联错误、焦点控制的带标签输入框。它不持有其值——绑定一个 @State 字符串。 |
PasswordStrengthBar | 纯由密码字符串驱动的三段式强度条;为空时隐藏。 |
OTPInputView | 六格一次性验证码输入;过滤非数字,通过 .oneTimeCode 自动填充,第六位落定时触发 onComplete。 |
容器(Containers)
| 组件 | 是什么 |
|---|---|
AppCard | 分组表面卡片(appGroupedSurface、圆角),包裹任意内容。 |
SectionHeader | 分组区块上方的大写眉标,iOS "设置"风格。 |
FlowLayout | 一个 Layout,把标签/徽章换行排列,而非滚出屏幕。 |
反馈:UiState 三件套
这三个渲染视图模型 UiState<T> 的各个分支(见架构):
| 组件 | 用于 |
|---|---|
LoadingState | .loading——居中转圈 + 可选说明 |
ErrorState | .error——图标、消息、可选重试 |
EmptyState | .data([])——图标、标题、消息、可选操作 |
外加 OfflineBanner——一条接入 NetworkObserver 的顶部
细横幅,以及 ThemeToggle(也算控件)。
媒体(Media)
| 组件 | 是什么 |
|---|---|
RemoteImage | Kingfisher KFImage 的薄封装(内存 + 磁盘缓存、淡入、重试一次)。要更换图片库,只改这一个文件。见存储。 |
组合一个屏幕
组件可预期地拼合到一起——对视图模型的状态做 switch,再依赖容器:
struct ExampleView: View {
@Environment(LocaleController.self) private var locale
@State private var viewModel: ExampleViewModel
var body: some View {
Group {
switch viewModel.state {
case .idle, .loading:
LoadingState(message: locale.t("common.loading"))
case .error(let message):
ErrorState(message: message) { Task { await viewModel.load() } }
case .data(let items) where items.isEmpty:
EmptyState(icon: "tray", title: locale.t("example.empty"))
case .data(let items):
ScrollView {
ForEach(items) { item in
AppCard { Text(item.title).font(.appHeadline) }
}
}
}
}
}
}注意那些 locale.t(...) 调用——面向用户的文案始终走本地化
辅助方法。
Toast
ToastController(Core/Toast/)是一个 @MainActor @Observable,通过 ToastHost
在 RootView 中作为浮层挂载一次。从任何地方用 AppEnvironment 上的控制器抛出一条
瞬时消息:
@Environment(AppEnvironment.self) private var env
// …
env.toast.show(locale.t("todos.cleared"), variant: .success)三种变体(info / success / error)决定图标与配色;success 与 error 还会
自动触发相应触感。Toast 在其时长后自动消失(默认 3 秒),可点按关闭,新的一条会取消
上一条的计时。
触感(Haptics)
Haptics.shared(Core/Haptics/)是一个 @MainActor 单例,用意图命名的方法封装了
UIFeedbackGenerator 家族:
Haptics.shared.selection() // 选择器 / 分段切换
Haptics.shared.light() // 轻微点按
Haptics.shared.medium()
Haptics.shared.heavy()
Haptics.shared.success() // 通知反馈
Haptics.shared.warning()
Haptics.shared.error()在你确知即将触发触感的时刻之前(例如 .onAppear 中)调用 Haptics.shared.prepare(),
以预热生成器、降低首次触发延迟。Toast 已会触发 success/error 触感,因此你很少直接
调用它们。
