SwiftUI笔记之属性包装器

90 阅读3分钟

1.@State

主要作用:在视图内部创建和修改状态变量,当状态变化时会自动触发视图的重新渲染。

作用范围:主要用于管理简单的值类型数据,如Bool,Int,String,Array等。

特点:@State变量应该是私有的,使用private关键字。

绑定:当需要从子视图修改状态时使用$前缀创建绑定。

生命周期:状态数据与视图生命周期绑定,视图销毁时状态也会被销毁。

示例:

@State private var counter = 0  

2.@StateObject

主要作用:管理可观察对象(ObservableObject),Swift 5.5和iOS 14+引入的特性,主要解决对象重复初始化的潜在问题。

作用范围:主要用于引用类型(class),如自定义对象等。

特点:被@StateObject包装后的对象只初始化一次。

生命周期:管理ObservableObject的生命周期,确保对象不会在视图重建时被意外销毁。

示例:

Class User: ObservableObject {
    @Published var name = "Jack”
    @Published var age = 20
}

Struct ChildView: View {
    @StateObject private var user = User()
}

3.@AppStorage

主要作用:简化对UserDefaults的读写操作,并实现数据的持久化存储。

作用范围:主要支持以下数据类型Int,Double,String,Bool,Data,URL等。

特点:值改变时,自动同步到UserDefaults,视图会自动更新。

生命周期:存储在本地沙盒中,当App被删除后销毁。

示例:

@AppStorage(“count”) private var count = 0 

4.@ViewBuilder的作用:主要用于构建视图层次结构

1.组合多个视图:把多个视图放在一起作为一个整体

代码示例:

struct CombinedView: View {
    var body: some View {
        VStack {
            Text("标题")
            Divider()
            Text("内容")
        }
    }
}

2.支持条件逻辑:可使用if/switch等语句

代码示例:

struct ConditionalView: View {
    @State var showDetails = false
    var body: some View {
        VStack {
            if showDetails {
                Text("详细信息").font(.title)
            } else {
                Image(systemName: "info.circle")
            }
            Button(showDetails ? "隐藏" : "显示") {
                showDetails.toggle()
            }
        }
    }
}

3.支持有限偱环:可以在视图构建中使用ForEach

4.简化视图返回:无需return,闭包内直接列出视图

5.自定义可复用视图:

struct CustomContainer<Content: View>: View {
    let title: String
    @ViewBuilder let content: () -> Content
    var body: some View {
        VStack {
            Text(title).font(.headline)
            Divider()
            content() // 使用 ViewBuilder 构建的内容
        }
        .padding()
    }
}

struct ContentView: View {
    var body: some View {
        CustomContainer(title: "用户信息") {
            if User.isLoggedIn {
                Text("欢迎回来")
                Button("登出") {}
            } else {
                Text("请登录")
                Button("登录") {}
            }
        }
    }
}

6.应用范围
1.修饰方法(最常用)
示例:

    //👉 @ViewBuilder 修饰的方法
    @ViewBuilder
    private func userCard(for user: User? = nil) -> some View {
        if let user = user {
            VStack {
                Image(systemName: "person.circle")
                    .font(.largeTitle)
                Text(user.name)
            }
            .padding()
            .background(Color.blue.opacity(0.1))
            .cornerRadius(10)
        } else {
            Text("请登录")
                .padding()
                .foregroundColor(.gray)
        }
    }

2.修饰属性(计算属性)

示例:

//👉 @ViewBuilder 修饰的计算属性
@ViewBuilder
private var premiumBanner: some View {
     if showPremium {
         HStack {
             Image(systemName: "crown.fill")
                 .foregroundColor(.yellow)
             Text("尊享VIP会员")
             Spacer()
             Button("关闭") {
                 showPremium = false
             }
         }
         .padding()
         .background(Color.purple.opacity(0.2))
         .cornerRadius(8)
     }
 }

3.修饰函数参数(创建自定义容器视图)

示例:

//👉 @ViewBuilder 修饰函数参数
struct CardView<Content: View>: View {
    let title: String
    let systemIcon: String
    @ViewBuilder let content: Content *//* 视图构建闭包
    var body: some View {
        VStack(alignment: .leading) {
            Label(title, systemImage: systemIcon)
                .font(.headline)
                .padding(.bottom, 5)
            Divider()
            content
                .padding(.top, 5)
        }
        .padding()
        .background(
            RoundedRectangle(cornerRadius: 12)
                .fill(Color(.secondarySystemBackground))
        )
    }
}