SwiftUI 属性包装器详解

Posted by Buddy on July 10, 2024

SwiftUI 是 Apple 于 2019 年 WWDC 上发布的新 UI 框架,它简化了界面开发,使得开发者可以使用声明式语法构建用户界面。在 SwiftUI 中,属性包装器(Property Wrappers)是一个非常重要的概念,它们被用来管理视图状态和数据绑定。本文将详细介绍 SwiftUI 中常用的属性包装器,包括 @AppStorage@Binding@EnvironmentObject@FocusedBinding@GestureState@Namespace@ObservedObjectObservableObject@SceneStorage@State@StateObject 以及 @UIApplicationDelegateAdaptor。本文不仅会解释每个属性包装器的作用和原理,还会给出具体的使用示例,并探讨它们之间的区别和注意事项。

@State

作用和原理

@State 是 SwiftUI 中最基础的属性包装器之一,它用来声明视图的局部状态。通过使用 @State,SwiftUI 可以在状态变化时自动重新渲染视图。

示例

import SwiftUI

struct CounterView: View {
    @State private var count = 0

    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button(action: {
                count += 1
            }) {
                Text("Increment")
            }
        }
    }
}

注意事项

  • @State 属性只能在结构体(struct)类型中使用。
  • 只能在视图的局部范围内使用,不应传递到子视图中使用。

@Binding

作用和原理

@Binding 用于在不同视图之间共享和同步状态。它通常用于子视图与父视图之间的状态传递,使得子视图可以修改父视图的状态。

示例

import SwiftUI

struct ParentView: View {
    @State private var isOn = false

    var body: some View {
        ToggleView(isOn: $isOn)
    }
}

struct ToggleView: View {
    @Binding var isOn: Bool

    var body: some View {
        Toggle("Toggle", isOn: $isOn)
    }
}

注意事项

  • @Binding 属性必须从其他地方传入绑定的值,通常是父视图。
  • @Binding 不持有数据,只是一个引用,不能独立存在。

@ObservedObject 和 ObservableObject

作用和原理

@ObservedObjectObservableObject 用于管理复杂的数据和状态,并在数据发生变化时通知视图更新。

示例

import SwiftUI
import Combine

class TimerModel: ObservableObject {
    @Published var counter = 0

    private var timer: Timer?

    func start() {
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
            self.counter += 1
        }
    }

    func stop() {
        timer?.invalidate()
        timer = nil
    }
}

struct TimerView: View {
    @ObservedObject var model = TimerModel()

    var body: some View {
        VStack {
            Text("Counter: \(model.counter)")
            Button("Start") {
                model.start()
            }
            Button("Stop") {
                model.stop()
            }
        }
    }
}

注意事项

  • ObservableObject 类的属性需要使用 @Published 修饰,这样属性的变化才能被视图检测到。
  • @ObservedObject 可以在多个视图中使用,但不会管理其生命周期。

@StateObject

作用和原理

@StateObject 是 SwiftUI 2.0 引入的一个新属性包装器,用于创建和管理 ObservableObject 的生命周期。与 @ObservedObject 不同,@StateObject 只应在对象的初始化时使用一次。

示例

import SwiftUI

class CounterModel: ObservableObject {
    @Published var count = 0

    func increment() {
        count += 1
    }
}

struct CounterStateObjectView: View {
    @StateObject private var model = CounterModel()

    var body: some View {
        VStack {
            Text("Count: \(model.count)")
            Button("Increment") {
                model.increment()
            }
        }
    }
}

注意事项

  • @StateObject 应该在视图的初始化时使用,只使用一次。
  • 在视图的更新过程中,@StateObject 保证对象实例不会被重新创建。

@EnvironmentObject

作用和原理

@EnvironmentObject 用于在视图层次结构中共享数据。它类似于依赖注入,可以让多个视图访问相同的数据对象。

示例

import SwiftUI

class UserSettings: ObservableObject {
    @Published var username: String = "Guest"
}

struct ProfileView: View {
    @EnvironmentObject var settings: UserSettings

    var body: some View {
        Text("Username: \(settings.username)")
    }
}

struct ContentView: View {
    var body: some View {
        ProfileView().environmentObject(UserSettings())
    }
}

注意事项

  • @EnvironmentObject 依赖于 SwiftUI 环境中的对象,需要使用 .environmentObject() 在父视图中注入。
  • 使用 @EnvironmentObject 的视图必须在视图层次结构中能够访问到注入的对象,否则会导致运行时错误。

@AppStorage

作用和原理

@AppStorage 用于将视图的状态与 UserDefaults 绑定,从而实现数据的持久化存储。

示例

import SwiftUI

struct SettingsView: View {
    @AppStorage("username") private var username: String = "Guest"

    var body: some View {
        VStack {
            TextField("Username", text: $username)
            Text("Stored Username: \(username)")
        }
        .padding()
    }
}

注意事项

  • @AppStorage 只能存储基本的数据类型(如 StringIntBool 等)。
  • 数据存储在 UserDefaults 中,所以需要确保存储的数据量较小。

@SceneStorage

作用和原理

@SceneStorage 用于在多个应用场景中存储数据。当应用场景发生变化时(例如在 iPad 上的多窗口环境),@SceneStorage 可以保留数据。

示例

import SwiftUI

struct SceneStorageView: View {
    @SceneStorage("note") private var note: String = ""

    var body: some View {
        TextEditor(text: $note)
            .padding()
    }
}

注意事项

  • @SceneStorage 主要用于在 iPad 的多窗口环境中保留数据。
  • 类似于 @AppStorage,但专注于场景特定的数据存储。

@FocusedBinding

作用和原理

@FocusedBinding 用于在当前焦点上下文中绑定数据,通常用于处理键盘焦点和输入。

示例

import SwiftUI

struct FocusedBindingView: View {
    @FocusState private var isTextFieldFocused: Bool

    var body: some View {
        TextField("Enter text", text: .constant(""))
            .focused($isTextFieldFocused)
            .padding()
    }
}

注意事项

  • @FocusedBinding 需要与 @FocusState 结合使用。
  • 用于处理视图中的焦点状态,通常用于表单输入和键盘管理。

@GestureState

作用和原理

@GestureState 用于跟踪手势状态变化,适用于手势识别和处理。

示例

import SwiftUI

struct GestureStateView: View {
    @GestureState private var isDragging = false

    var body: some View {
        Circle()
            .fill(isDragging ? Color.green : Color.blue)
            .frame(width: 100, height: 100)
            .gesture(
                DragGesture()
                    .updating($isDragging) { value, state, transaction in
                        state = true
                    }
            )
    }
}

注意事项

  • @GestureState 用于在手势过程中跟踪状态,手势结束后状态会自动重置。
  • 适用于复杂的手势处理和动画效果。

@Namespace

作用和原理

@Namespace 用于定义 SwiftUI 的动画命名空间,常用于视图过渡和匹配动画。

示例

import SwiftUI

struct NamespaceView: View {
    @Namespace private var animation

    @State private var isExpanded = false

    var body: some View {
        VStack {
            if isExpanded {
                RoundedRectangle(cornerRadius: 25.0)
                    .matchedGeometryEffect(id: "shape", in: animation)
                    .frame(width: 300, height: 200)
            } else {
                RoundedRectangle(cornerRadius: 25.0)
                    .matchedGeometryEffect(id: "shape", in: animation)
                    .frame(width: 100, height: 

100)
            }
        }
        .onTapGesture {
            withAnimation {
                isExpanded.toggle()
            }
        }
    }
}

注意事项

  • @Namespace 用于动画过渡,需要与 matchedGeometryEffect 一起使用。
  • @Namespace 声明的命名空间可以在多个视图之间共享。

@UIApplicationDelegateAdaptor

作用和原理

@UIApplicationDelegateAdaptor 用于将自定义的 UIApplicationDelegate 实现注入到 SwiftUI 的 App 生命周期中。

示例

import SwiftUI

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Custom setup
        return true
    }
}

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

注意事项

  • @UIApplicationDelegateAdaptor 主要用于需要自定义 UIApplicationDelegate 行为的场景。
  • 在 SwiftUI 中使用传统的 AppDelegate 方法时非常有用。

@Environment

作用和原理

@Environment 用于读取 SwiftUI 环境中的值。SwiftUI 环境是一个动态属性集合,可以传递应用中的共享数据,比如颜色方案、尺寸类别等。

示例

import SwiftUI

struct EnvironmentView: View {
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Text("Current color scheme: \(colorScheme == .dark ? "Dark" : "Light")")
            .padding()
    }
}

注意事项

  • @Environment 属性只能读取环境中的值,不能修改它们。
  • 要将值注入到环境中,可以使用 .environment() 修饰符。

@Environment(.managedObjectContext)

作用和原理

@Environment(\.managedObjectContext) 是 Core Data 的特定环境值,用于将 NSManagedObjectContext 注入到 SwiftUI 视图中。

示例

import SwiftUI
import CoreData

struct CoreDataView: View {
    @Environment(\.managedObjectContext) private var viewContext

    var body: some View {
        Button("Add Item") {
            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()

            do {
                try viewContext.save()
            } catch {
                // Handle error
            }
        }
    }
}

注意事项

  • 使用 Core Data 时,需要在应用的入口视图中将 NSManagedObjectContext 注入环境中。

@FetchRequest

作用和原理

@FetchRequest 是用于从 Core Data 中获取数据的属性包装器。它会自动执行指定的 fetch 请求,并在数据更改时更新视图。

示例

import SwiftUI
import CoreData

struct FetchRequestView: View {
    @FetchRequest(
        entity: Item.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)]
    ) var items: FetchedResults<Item>

    var body: some View {
        List(items) { item in
            Text("Item at \(item.timestamp!, formatter: dateFormatter)")
        }
    }
}

注意事项

  • @FetchRequest 只能在视图中使用,用于自动管理 Core Data 数据的获取和更新。
  • 需要确保数据模型和 fetch 请求正确配置。

@ScaledMetric

作用和原理

@ScaledMetric 用于根据用户的动态类型设置调整字体大小等视图尺寸。它可以确保视图在不同的字体设置下具有良好的可读性和一致性。

示例

import SwiftUI

struct ScaledMetricView: View {
    @ScaledMetric var fontSize: CGFloat = 20

    var body: some View {
        Text("Hello, World!")
            .font(.system(size: fontSize))
            .padding()
    }
}

注意事项

  • @ScaledMetric 适用于需要根据用户设置动态调整尺寸的视图。
  • 确保使用 @ScaledMetric 属性包装器时设置合适的默认值。

@UIApplicationDelegateAdaptor

作用和原理

@UIApplicationDelegateAdaptor 用于将自定义的 UIApplicationDelegate 实现注入到 SwiftUI 的 App 生命周期中。

示例

import SwiftUI

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Custom setup
        return true
    }
}

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

注意事项

  • @UIApplicationDelegateAdaptor 主要用于需要自定义 UIApplicationDelegate 行为的场景。
  • 在 SwiftUI 中使用传统的 AppDelegate 方法时非常有用。

@Environment(.presentationMode)

作用和原理

@Environment(\.presentationMode) 用于控制视图的显示和隐藏状态,通常用于模态视图的关闭操作。

示例

import SwiftUI

struct PresentationModeView: View {
    @Environment(\.presentationMode) var presentationMode

    var body: some View {
        Button("Dismiss") {
            presentationMode.wrappedValue.dismiss()
        }
        .padding()
    }
}

注意事项

  • @Environment(\.presentationMode) 只能用于控制当前视图的显示和隐藏。
  • 确保在需要控制视图显示状态的地方正确使用。

@FocusState

作用和原理

@FocusState 用于管理视图中的焦点状态,通常用于处理文本输入焦点。

示例

import SwiftUI

struct FocusStateView: View {
    @FocusState private var isFocused: Bool

    var body: some View {
        TextField("Enter text", text: .constant(""))
            .focused($isFocused)
            .padding()
        Button("Toggle Focus") {
            isFocused.toggle()
        }
    }
}

注意事项

  • @FocusState 用于管理输入焦点状态,需要与 focused 修饰符一起使用。
  • 适用于表单输入和焦点管理。

@Environment(.locale)

作用和原理

@Environment(\.locale) 用于读取当前视图环境中的 Locale 对象。Locale 包含了应用的语言和地区设置。

示例

import SwiftUI

struct LocaleView: View {
    @Environment(\.locale) var locale

    var body: some View {
        Text("Current locale: \(locale.identifier)")
            .padding()
    }
}

注意事项

  • @Environment(\.locale) 只能读取环境中的 Locale 值,不能直接修改它们。
  • 要改变应用的 Locale,需要在应用设置中进行调整。

@Environment(.calendar)

作用和原理

@Environment(\.calendar) 用于读取当前视图环境中的 Calendar 对象。Calendar 包含了应用的日历设置。

示例

import SwiftUI

struct CalendarView: View {
    @Environment(\.calendar) var calendar

    var body: some View {
        Text("Current calendar: \(calendar.identifier)")
            .padding()
    }
}

注意事项

  • @Environment(\.calendar) 只能读取环境中的 Calendar 值,不能直接修改它们。
  • 通常用于显示和处理日期相关的数据。

@Environment(.timeZone)

作用和原理

@Environment(\.timeZone) 用于读取当前视图环境中的 TimeZone 对象。TimeZone 包含了应用的时区设置。

示例

import SwiftUI

struct TimeZoneView: View {
    @Environment(\.timeZone) var timeZone

    var body: some View {
        Text("Current time zone: \(timeZone.identifier)")
            .padding()
    }
}

注意事项

  • @Environment(\.timeZone) 只能读取环境中的 TimeZone 值,不能直接修改它们。
  • 用于处理与时区相关的数据。

@ScaledMetric

作用和原理

@ScaledMetric 用于根据用户的动态类型设置调整字体大小等视图尺寸。它可以确保视图在不同的字体设置下具有良好的可读性和一致性。

示例

import SwiftUI

struct ScaledMetricView: View {
    @ScaledMetric var fontSize: CGFloat = 20

    var body: some View {
        Text("Hello, World!")
            .font(.system(size: fontSize))
            .padding()
    }
}

注意事项

  • @ScaledMetric 适用于需要根据用户设置动态调整尺寸的视图。
  • 确保使用 @ScaledMetric 属性包装器时设置合适的默认值。

@Environment(.accessibilityEnabled)

作用和原理

@Environment(\.accessibilityEnabled) 用于读取当前视图环境中的无障碍设置,检查无障碍功能是否启用。

示例

import SwiftUI

struct AccessibilityEnabledView: View {
    @Environment(\.accessibilityEnabled) var accessibilityEnabled

    var body: some View {
        Text("Accessibility is \(accessibilityEnabled ? "enabled" : "disabled")")
            .padding()
    }
}

注意事项

  • @Environment(\.accessibilityEnabled) 只能读取环境中的无障碍设置值,不能直接修改它们。
  • 用于调整视图的行为和外观以适应无障碍要求。

@Environment(.dismiss)

作用和原理

@Environment(\.dismiss) 用于获取一个操作,用来关闭当前的视图。通常用于模态视图和导航视图的关闭操作。

示例

import SwiftUI

struct DismissView: View {
    @Environment(\.dismiss) var dismiss

    var body: some View {
        Button("Dismiss") {
            dismiss()
        }
        .padding()
    }
}

注意事项

  • @Environment(\.dismiss) 只能用于关闭当前显示的视图。
  • 确保在需要控制视图关闭的地方正确使用。

@ObservedResults

作用和原理

@ObservedResults 用于观察和管理从 Realm 数据库中获取的数据。在数据更改时,自动更新视图。

示例

import SwiftUI
import RealmSwift

class Task: Object, ObjectKeyIdentifiable {
    @Persisted(primaryKey: true) var id: ObjectId
    @Persisted var name: String = ""
    @Persisted var isCompleted: Bool = false
}

struct TaskListView: View {
    @ObservedResults(Task.self) var tasks

    var body: some View {
        List {
            ForEach(tasks) { task in
                Text(task.name)
            }
        }
    }
}

注意事项

  • @ObservedResults 只能用于从 Realm 数据库中获取数据。
  • 需要确保 Realm 数据库和模型类正确配置。

@Query

作用和原理

@Query 是用于 Firestore 的 SwiftUI 属性包装器。它可以自动查询 Firestore 数据,并在数据变化时更新视图。

示例

import SwiftUI
import FirebaseFirestoreSwift

struct User: Identifiable, Codable {
    @DocumentID var id: String?
    var name: String
}

struct UsersView: View {
    @Query(collectionPath: "users") var users: [User]

    var body: some View {
        List(users) { user in
            Text(user.name)
        }
    }
}

注意事项

  • @Query 只能用于 Firestore 数据库。
  • 需要确保 Firestore 和模型类正确配置。

@ViewBuilder

作用和原理

@ViewBuilder 并不是一个属性包装器,而是一种结果构建器,它用于简化和增强视图构建器的声明。它允许你在单个视图构建器中返回多个视图。

示例

import SwiftUI

struct ViewBuilderExample: View {
    var body: some View {
        VStack {
            content
        }
    }

    @ViewBuilder
    var content: some View {
        Text("Hello, World!")
        Text("This is another text")
    }
}

注意事项

  • @ViewBuilder 主要用于简化视图构建器的代码,特别是在返回多个视图的情况下。
  • 只能用于视图构建器函数中。

@ObservedRealmObject

作用和原理

@ObservedRealmObject 用于观察和管理来自 Realm 数据库的对象。在数据更改时自动更新视图。

示例

import SwiftUI
import RealmSwift

class Task: Object, ObjectKeyIdentifiable {
    @Persisted(primaryKey: true) var id: ObjectId
    @Persisted var name: String = ""
    @Persisted var isCompleted: Bool = false
}

struct TaskDetailView: View {
    @ObservedRealmObject var task: Task

    var body: some View {
        VStack {
            TextField("Task Name", text: $task.name)
            Toggle("Completed", isOn: $task.isCompleted)
        }
        .padding()
    }
}

注意事项

  • @ObservedRealmObject 只能用于从 Realm 数据库中获取数据。
  • 需要确保 Realm 数据库和模型类正确配置。

@PreferenceKey

作用和原理

@PreferenceKey 用于定义和读取视图层次结构中的自定义首选项值。它允许在父视图和子视图之间传递数据。

示例

import SwiftUI

struct PreferenceKeyExample: View {
    var body: some View {
        VStack {
            Text("Hello, World!")
                .anchorPreference(key: BoundsPreferenceKey.self, value: .bounds) { $0 }
        }
        .overlayPreferenceValue(BoundsPreferenceKey.self) { preferences in
            GeometryReader { geometry in
                if let bounds = preferences.first {
                    Rectangle()
                        .stroke()
                        .frame(width: bounds.width, height: bounds.height)
                        .offset(x: bounds.minX, y: bounds.minY)
                }
            }
        }
    }
}

struct BoundsPreferenceKey: PreferenceKey {
    static var defaultValue: [Anchor<CGRect>] = []

    static func reduce(value: inout [Anchor<CGRect>], nextValue: () -> [Anchor<CGRect>]) {
        value.append(contentsOf: nextValue())
    }
}

注意事项

  • @PreferenceKey 主要用于在视图层次结构中传递和读取自定义数据。
  • 需要定义自定义的 PreferenceKey 类型。

@AppStorage

作用和原理

@AppStorage 用于将值存储在用户默认数据库中,并在值改变时自动更新视图。

示例

import SwiftUI

struct AppStorageExample: View {
    @AppStorage("username") var username: String = ""

    var body: some View {
        VStack {
            TextField("Username", text: $username)
            Text("Stored username: \(username)")
        }
        .padding()
    }
}

注意事项

  • @AppStorage 适用于需要在应用重启后持久化存储数据的场景。
  • 使用时需要提供一个唯一的键来存储和检索数据。

@Environment(.openURL)

作用和原理

@Environment(\.openURL) 用于获取一个操作,用来打开指定的 URL。它通常用于在 SwiftUI 应用中处理 URL 打开操作。

示例

import SwiftUI

struct OpenURLExample: View {
    @Environment(\.openURL) var openURL

    var body: some View {
        Button("Open Apple Website") {
            openURL(URL(string: "https://www.apple.com")!)
        }
        .padding()
    }
}

注意事项

  • @Environment(\.openURL) 只能用于打开 URL,不适用于其他用途。
  • 确保提供有效的 URL。

@FocusState

作用和原理

@FocusState 用于管理视图中的焦点状态,通常用于处理文本输入焦点。

示例

import SwiftUI

struct FocusStateExample: View {
    @FocusState private var isFocused: Bool

    var body: some View {
        TextField("Enter text", text: .constant(""))
            .focused($isFocused)
            .padding()
        Button("Toggle Focus") {
            isFocused.toggle()
        }
    }
}

注意事项

  • @FocusState 用于管理输入焦点状态,需要与 focused 修饰符一起使用。
  • 适用于表单输入和焦点管理。

属性包装器总结与对比

在 SwiftUI 中,属性包装器用于管理视图状态和数据绑定。以下是所有提到的属性包装器的简短总结和对比:

1. @State

  • 作用:用于声明视图的本地状态。
  • 特点:状态改变时会重新渲染视图。
  • 示例@State private var isActive: Bool = false

2. @Binding

  • 作用:在父子视图之间共享状态。
  • 特点:父视图将状态传递给子视图进行双向绑定。
  • 示例@Binding var isActive: Bool

3. @EnvironmentObject

  • 作用:在视图层次结构中共享对象。
  • 特点:视图可以从环境中读取共享的数据对象。
  • 示例@EnvironmentObject var model: DataModel

4. @ObservedObject

  • 作用:观察和响应对象的状态变化。
  • 特点:用于在多个视图中观察同一个对象。
  • 示例@ObservedObject var model: DataModel

5. @StateObject

  • 作用:用于初始化和持有对象的状态。
  • 特点:视图在对象改变时重新渲染。
  • 示例@StateObject var model: DataModel

6. @AppStorage

  • 作用:将值存储在用户默认数据库中。
  • 特点:持久化存储数据,并在值改变时更新视图。
  • 示例@AppStorage("username") var username: String = ""

7. @SceneStorage

  • 作用:在场景中保存和恢复视图状态。
  • 特点:在应用切换场景时保持状态。
  • 示例@SceneStorage("text") var text: String = ""

8. @GestureState

  • 作用:用于跟踪手势状态。
  • 特点:适用于在手势识别过程中暂存状态。
  • 示例@GestureState private var dragOffset = CGSize.zero

9. @Namespace

  • 作用:创建动画的命名空间。
  • 特点:用于定义视图动画的共享命名空间。
  • 示例@Namespace var animation

10. @UIApplicationDelegateAdaptor

  • 作用:将自定义的 UIApplicationDelegate 注入到 SwiftUI 应用中。
  • 特点:适用于需要自定义应用代理行为的场景。
  • 示例@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

11. @Environment(.presentationMode)

  • 作用:控制视图的显示和隐藏状态。
  • 特点:用于模态视图的关闭操作。
  • 示例@Environment(\.presentationMode) var presentationMode

12. @FocusState

  • 作用:管理视图中的焦点状态。
  • 特点:用于处理文本输入焦点。
  • 示例@FocusState private var isFocused: Bool

13. @Environment(.locale)

  • 作用:读取当前视图环境中的 Locale 对象。
  • 特点:用于显示和处理区域设置相关的数据。
  • 示例@Environment(\.locale) var locale

14. @Environment(.calendar)

  • 作用:读取当前视图环境中的 Calendar 对象。
  • 特点:用于显示和处理日期相关的数据。
  • 示例@Environment(\.calendar) var calendar

15. @Environment(.timeZone)

  • 作用:读取当前视图环境中的 TimeZone 对象。
  • 特点:用于处理与时区相关的数据。
  • 示例@Environment(\.timeZone) var timeZone

16. @Environment(.accessibilityEnabled)

  • 作用:读取当前视图环境中的无障碍设置。
  • 特点:用于调整视图以适应无障碍要求。
  • 示例@Environment(\.accessibilityEnabled) var accessibilityEnabled

17. @Environment(.dismiss)

  • 作用:获取一个操作,用来关闭当前视图。
  • 特点:用于模态视图和导航视图的关闭操作。
  • 示例@Environment(\.dismiss) var dismiss

18. @ObservedResults

  • 作用:观察和管理来自 Realm 数据库的数据。
  • 特点:在数据更改时自动更新视图。
  • 示例@ObservedResults(Task.self) var tasks

19. @Query

  • 作用:用于 Firestore 数据库的数据查询。
  • 特点:自动查询数据,并在数据变化时更新视图。
  • 示例@Query(collectionPath: "users") var users: [User]

20. @ObservedRealmObject

  • 作用:观察和管理来自 Realm 数据库的对象。
  • 特点:在数据更改时自动更新视图。
  • 示例@ObservedRealmObject var task: Task

21. @PreferenceKey

  • 作用:定义和读取视图层次结构中的自定义首选项值。
  • 特点:在父视图和子视图之间传递数据。
  • 示例:定义自定义 PreferenceKey 类型并使用。

22. @ScaledMetric

  • 作用:根据用户的动态类型设置调整视图尺寸。
  • 特点:确保视图在不同字体设置下具有良好的可读性和一致性。
  • 示例@ScaledMetric var fontSize: CGFloat = 20

对比

  • 状态管理@State@Binding@StateObject@ObservedObject
  • 数据存储@AppStorage@SceneStorage
  • 环境数据@Environment@EnvironmentObject@Environment(\.locale)@Environment(\.calendar)@Environment(\.timeZone)@Environment(\.accessibilityEnabled)@Environment(\.dismiss)@Environment(\.openURL)
  • 手势状态@GestureState
  • 动画@Namespace
  • 应用代理@UIApplicationDelegateAdaptor
  • 焦点管理@FocusState
  • 数据查询@ObservedResults@Query
  • 自定义首选项@PreferenceKey
  • 动态尺寸@ScaledMetric

总结

SwiftUI 中的属性包装器提供了强大的工具集,使得开发者可以更方便地管理视图状态和数据绑定。每种属性包装器都有其特定的用途和使用场景,了解它们的作用、原理和用法,对于构建高效和健壮的 SwiftUI 应用至关重要。

通过本篇博客,我们详细介绍了 @AppStorage@Binding@EnvironmentObject@FocusedBinding@GestureState@Namespace@ObservedObjectObservableObject@SceneStorage@State@StateObject@UIApplicationDelegateAdaptor 这些属性包装器。希望这些内容能帮助你在实际开发中更好地使用 SwiftUI 的强大功能。