SwiftUI 多平台架构 (iOS、iPadOS、macOS、visionOS)

发布: (2026年1月7日 GMT+8 03:32)
5 min read
原文: Dev.to

I’m happy to translate the article for you, but I need the actual text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line, formatting, markdown, and any code blocks exactly as they are while translating the rest into Simplified Chinese.

🧠 核心原则

共享行为。
专门化呈现。

  • 业务逻辑应 100 % 共享。
  • UI 组合根据平台进行适配。

🧱 1. 按功能拆分,而不是按平台

不良结构

iOS/
macOS/
Shared/

良好结构

Features/
    Home/
    Profile/
    Settings/
Platform/
    iOS/
    macOS/
    visionOS/

每个功能包含:

  • ViewModel
  • State
  • Business logic

平台文件夹包含:

  • Wrappers
  • Layout adapters
  • Platform‑specific views

🧩 2. 平台抽象层

创建小型适配器:

protocol PlatformMetrics {
    var sidebarWidth: CGFloat { get }
    var toolbarHeight: CGFloat { get }
}

针对不同平台实现:

struct iOSMetrics: PlatformMetrics {
    let sidebarWidth: CGFloat = 0
    let toolbarHeight: CGFloat = 44
}

struct macOSMetrics: PlatformMetrics {
    let sidebarWidth: CGFloat = 240
    let toolbarHeight: CGFloat = 52
}

注入相应的实现:

.environment(\.metrics, currentMetrics)

视图内部不需要条件判断。

🧭 3. 每个平台的导航架构

平台导航风格
iPhone单栈,基于 push
iPad分割视图,列式导航
macOS侧边栏 + 详情,多窗口
visionOS空间栈,基于场景的导航

不要强制使用单一导航模型。相反:

struct RootView: View {
    var body: some View {
        PlatformContainer {
            HomeFeature()
        }
    }
}

PlatformContainer 根据当前平台切换实现。

🪟 4. 窗口与场景管理

macOS 与 visionOS 是以窗口为先的平台。请明确设计:

WindowGroup {
    RootView()
}

WindowGroup(id: "inspector") {
    InspectorView()
}

在 iOS 上这些组会被忽略;在 macOS 上它们是必不可少的。架构必须假设存在多个实例。

🧠 5. 输入模型差异

平台输入方式
iOS触摸、手势、滑动
macOS指针、悬停、右键点击、键盘
visionOS目光、捏合、空间聚焦

不要仅仅依赖:

.onTapGesture {  }

始终支持:

  • Button(包括键盘快捷键)
  • 焦点处理
  • 上下文菜单

⌨️ 6. 键盘与命令系统

macOS 与 iPad 需要命令定义:

.commands {
    CommandGroup(replacing: .newItem) {
        Button("New Item") {
            create()
        }
        .keyboardShortcut("N")
    }
}

从共享逻辑中暴露操作:

func create()
func delete()
func refresh()

UI 层将这些操作连接起来;底层逻辑保持共享。

📐 7. 布局策略

避免使用固定布局。使用自适应堆栈、灵活网格、动态文字大小和尺寸类。示例模式:

if horizontalSizeClass == .compact {
    CompactLayout()
} else {
    RegularLayout()
}

将此逻辑隔离在布局容器中——而不是放在功能视图中。

🧪 8. 测试多平台正确性

跨平台测试以下内容:

  • 窗口创建
  • 各平台的深度链接
  • 键盘导航与焦点行为
  • 分屏视图状态
  • 多窗口恢复

大多数多平台错误与状态相关,而非 UI 相关。

❌ 9. 常见反模式

避免:

  • #if os(iOS) 在特性视图内部
  • 在 ViewModel 中进行平台检查
  • 重复的业务逻辑
  • 强制在所有地方使用单一 UI 的导航 hack

如果一个解决方案感觉被强行拼凑,那它很可能就是。

🧠 10. 心智模型

分层思考:

Business Logic (shared)
State Management (shared)
Navigation Model (per platform)
Layout System (per platform)
Input Model (per platform)
Presentation (per platform)

只有最底部的三层会因平台而异。

🚀 最后思考

  • 功能保持可重用
  • 代码保持整洁
  • 平台保持原生体验
  • 维护保持理性
  • visionOS 的支持变得微不足道
Back to Blog

相关文章

阅读更多 »

SwiftUI #21:组

什么是 Group?Group 将多个视图聚合在一起,以避免 Stack 的子视图限制(最大 10),并允许对多个视图应用样式。

SwiftUI #20: 优先级

介绍 在 SwiftUI 中,Stack 会在其视图之间等距划分空间。如果视图放不下,它会为 Image 分配固定大小并进行缩减……