自定义数据类型UI绑定

场景:

在收货地址列表页面A中,点击一个地址进详情页面B,然后修改地址保存关闭页面B,收货地址A需要同步UI更新修改的信息。

机制:

1、在SwiftUI中,使用@Binding只能绑定基本数据类型,不能处理自定义数据类型。
2、@StateObject和@ObservedObject的监听,在目前的测试中体现的是向下传递。即页面A创建的模型数组,传递到页面B用@ObservedObject监听,然后在页面A延时修改了数据某个模型中的属性,这时页面A的UI不会更新,页面B的UI会更新。

点击查看问题代码
import SwiftUI

class FruitModelData: ObservableObject {
    @Published var fruits: [FruitModel] = [
        FruitModel(name: "Apple", count: 5),
        FruitModel(name: "Banana", count: 3)
    ]
}

struct ContentView1: View {
    @StateObject var fruitModelData: FruitModelData
    
    var body: some View {
        NavigationView {
            List {
                ForEach(fruitModelData.fruits) { fruit in
                    NavigationLink(destination: FruitDetail(fruit: fruit)) {
                        HStack {
                            Text(fruit.name)
                            Text("\(fruit.count)")
                        }
                    }
                }
            }
        }
    }
}

// FruitDetail.swift
struct FruitDetail: View {
    @ObservedObject var fruit: FruitModel
    
    var body: some View {
        VStack {
            Text("Name: \(fruit.name)")
            Text("Count: \(fruit.count)")
            
            Button("Increment Count") {
                fruit.count += 1
            }
        }
    }
}

struct DSTest_Previews: PreviewProvider {
    static var previews: some View {
        ContentView1(fruitModelData: FruitModelData())
    }
}
3、也可能学艺不精,还没学到这种场景适合的技术。

解决方案:

@Binding

通过上面的两个现象可以得出,要在页面B修改属性的时候,同时向上反馈更新页面A的UI,那就只能用到@Binding,所以做法是把模型拆分成基本数据类型

点击查看@Binding代码
import SwiftUI

class FruitModelData: ObservableObject {
    @Published var fruits: [FruitModel] = [
        FruitModel(name: "Apple", count: 5),
        FruitModel(name: "Banana", count: 3)
    ]
}

struct ContentView1: View {
    @StateObject var fruitModelData: FruitModelData
    
    var body: some View {
        NavigationView {
            List {
                ForEach(fruitModelData.fruits.indices, id: \.self) { i in
                    let model = fruitModelData.fruits[i]
                    NavigationLink(destination: FruitDetail(fruit: model, count: $fruitModelData.fruits[i].count)) {
                        HStack {
                            Text(model.name)
                            Text("\(model.count)")
                        }
                    }
                }
            }
        }
    }
}

// FruitDetail.swift
struct FruitDetail: View {
    @ObservedObject var fruit: FruitModel
    @Binding var count: Int
    
    var body: some View {
        VStack {
            Text("Name: \(fruit.name)")
            Text("Count: \(fruit.count)")
            
            Button("Increment Count") {
                count += 1
            }
        }
    }
}

struct DSTest_Previews: PreviewProvider {
    static var previews: some View {
        ContentView1(fruitModelData: FruitModelData())
    }
}

combine

既然我们修改单个模型中的属性无法触发更新,那我们就直接通知更新整个数组,这样使用到的UI都会刷新

点击查看objectWillChange代码

import SwiftUI

class FruitModelData: ObservableObject {
    @Published var fruits: [FruitModel] = [
        FruitModel(name: "Apple", count: 5),
        FruitModel(name: "Banana", count: 3)
    ]
}

struct ContentView1: View {
    @StateObject var fruitModelData: FruitModelData
    
    var body: some View {
        NavigationView {
            List {
                ForEach(fruitModelData.fruits) { fruit in
                    NavigationLink(destination: FruitDetail(fruit: fruit, fruitModelData: fruitModelData)) {
                        HStack {
                            Text(fruit.name)
                            Text("\(fruit.count)")
                        }
                    }
                }
            }
        }
    }
}

// FruitDetail.swift
struct FruitDetail: View {
    @ObservedObject var fruit: FruitModel
    var fruitModelData: FruitModelData //这里把整个数组的对象传递过来
    
    var body: some View {
        VStack {
            Text("Name: \(fruit.name)")
            Text("Count: \(fruit.count)")
            
            Button("Increment Count") {
                fruit.count += 1
                //既然修改其中一个模型触发不了,那我就通知你整个模型,我已经更新了数据,但是需要集成ObservableObject
                fruitModelData.objectWillChange.send()
            }
        }
    }
}

struct DSTest_Previews: PreviewProvider {
    static var previews: some View {
        ContentView1(fruitModelData: FruitModelData())
    }
}
posted @   dasonxie  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示