SwiftUI App Structure

SwiftUI 与传统的 UIKit 思路不同,是一种声明式 UI 框架,这种框架的特点就是摒弃了传统开发的代码按生命周期进行的流程概念,直接通过声明所呈现的内容来与用户进行交互。

App

swift 复制代码
protocol App

App 代表了应用程序的抽象,需要在它的 body 属性中声明应用所能够呈现的内容:

swift 复制代码
@main 
struct MyApp: App { 
    var body: some Scene { 
        WindowGroup { 
            Text("Hello, world!") 
        } 
    } 
}

在你的自定义实现结构体声明之上添加 @main,用来标记这是应用程序的唯一主入口。同时,这也意味着你的应用程序只能有这一个主入口。

Scene

App 的 body 属性中,可以组合一个或多个 Scene 的实现,每一个 Scene 实现包含视图结构的根视图,代表用户界面中的内容,也可能是一部分(多窗口),它的生命周期由系统管理。

SwiftUI 提供了一些 Scene 的实现来表示场景的场景,包括显示设置或是文档。 你也可以自定义创建 Scene,但其实就是组合一些系统提供的 Scene:

swift 复制代码
struct MyScene: Scene {
    var body: some Scene {
        WindowGroup {
            MyRootView()
        }
    }
}

Scene 有一些常见实现:

  • WindowGroup
  • Settings
  • Window
  • ImmersiveSpace
  • DocumentGroup
  • ...

SwiftUI 是跨平台框架,所以基于不同的平台支持的 Scene 也有所不同。例如,visionOS 不支持 Window,而 ImmersiveSpace 是 visionOS 独有的。

App 的 body 中可以容纳一个或多个 Scene:

swift 复制代码
@main
struct Mail: App {

    var body: some Scene {
        WindowGroup {
            MailViewer()
        }
        Settings {
            SettingsView() 
        }
    }
}

应用启动,会默认打开第一个 Scene 所呈现的内容 。针对不同的平台,可能需要修改 plist 来支持多场景。例如,在 visionOS 平台或 iPadOS,需要添加 Enable Mutiple Windows 为 YES。

Scene 本质上就是呈现 View 结构的容器,系统会决定他们的显示行为,例如,在 iPadOS 或 macOS 支持多窗口,用户就可以创建或是删除一些窗口;而在 iOS 平台(or 其他)当应用处于活跃状态,视图内容将会占满整个屏幕。

Scene 的生命周期

可以通过环境值 scenePhase 来从 Scene 或 View 中读取当前 Scene 是否处于活跃状态:

swift 复制代码
struct MyScene: Scene {
    @Environment(\.scenePhase) private var scenePhase


    // ...
}

scenePhase 是枚举类型 ScenePhase,包括:

  • background:处于后台,不可交互;
  • inactive:处于前台,不可交互;
  • active:处于前台,可以交互。

Scene 提供了一些方法,可以对 Scene 进行配置,例如可以使用 onChange(of:perform) 来监听某个值的变化,从而触发一些操作,下面是一个当应用进入后台后清除缓存的操作:

swift 复制代码
struct MyScene: Scene {
    @Environment(\.scenePhase) private var scenePhase
    @StateObject private var cache = DataCache()


    var body: some Scene {
        WindowGroup {
            MyRootView()
        }
        .onChange(of: scenePhase) { newScenePhase in
            if newScenePhase == .background {
                cache.empty()
            }
        }
    }
}

Scene 之间的通信

多个 Scene 可以通过在 App 中声明一些状态来进行通信。例如,使用 @StateObject 来初始化一个数据类,然后将数据类作为 ObservedObject 或通过环境作为 EnvironmentObject 提供给 Scene:

swift 复制代码
@main
struct Mail: App {
    @StateObject private var model = MailModel()


    var body: some Scene {
        WindowGroup {
            MailViewer()
                .environmentObject(model) // Passed through the environment.
        }
        Settings {
            SettingsView(model: model) // Passed as an observed object.
        }
    }
}

总结

SwiftUI App 以 App 协议的实现为应用主入口,其 body 属性中可以配置多个 Scene,App 启动时默认打开第一个 Scene。 Scene 代表用户界面的容器,用来承载视图结构,其内容是视图结构的根视图。Scene 具有生命周期,包括三种:

  1. backgroud
  2. inactive
  3. active 可以通过环境属性 scenePhase 来查询。 Scene 直接可以通过在 App 中定义共享的数据结构来共享数据。可以通过一些方法或通过参数的形式传递到不同的 Scene。
相关推荐
货拉拉技术10 天前
货拉拉用户端SwiftUI踩坑之旅
ios·swiftui·swift
ZacJi13 天前
巧用 allowsHitTesting 自定义 SignInWithAppleButton
ios·swiftui·swift
刘争Stanley15 天前
SwiftUI 是如何改变 iOS 开发游戏规则的?
ios·swiftui·swift
1024小神16 天前
在swiftui中使用Alamofire发送请求获取github仓库里的txt文件内容并解析
ios·github·swiftui
大熊猫侯佩19 天前
SwiftUI 撸码常见错误 2 例漫谈
swiftui·xcode·tag·tabview·preview·coredata·fetchrequest
东坡肘子1 个月前
肘子的 Swift 周报 #063|异种肾脏移植取得突破
swiftui·swift·apple
恋猫de小郭1 个月前
什么?Flutter 可能会被 SwiftUI/ArkUI 化?全新的 Flutter Roadmap
flutter·ios·swiftui
靴子学长1 个月前
iOS + watchOS Tourism App(含源码可简单复现)
mysql·ios·swiftui
hxx2211 个月前
iOS swift开发系列--如何给swiftui内容视图添加背景图片显示
ios·swiftui·swift
胖虎11 个月前
SwiftUI - (十九)组合视图
ios·swiftui·swift·组合视图