在内容视图 SwiftUI 中更新对象数组

Posted

技术标签:

【中文标题】在内容视图 SwiftUI 中更新对象数组【英文标题】:Updating array of objects in Content View SwiftUI 【发布时间】:2021-12-27 21:31:13 【问题描述】:

我在 ContentView 中创建了一个数组,当有人拖动对象时我可以更改它的上下文。在 ContentView 中,我有一个数组 nodes.n_array,它是一个 Node 对象数组。在 ForEach(in ContentView) 我尝试检测拖动对象并更改它的坐标。它不起作用。

节点类:

import Foundation
import SwiftUI

class Node: Decodable, ObservableObject 
    enum CodingKeys: CodingKey 
        case id, x, y, text, red, green, blue, shape
    
    
    
    public let id: Int
    @Published var x: Double
    @Published var y: Double
    public let text: String
    public var red: Double
    public var green: Double
    public var blue: Double
    public var shape: Int
    
    required init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        x = try container.decode(Double.self, forKey: .x)
        y = try container.decode(Double.self, forKey: .y)
        text = try container.decode(String.self, forKey: .text)
        red = try container.decode(Double.self, forKey: .red)
        green = try container.decode(Double.self, forKey: .green)
        blue = try container.decode(Double.self, forKey: .blue)
        shape = try container.decode(Int.self, forKey: .shape)
    

    
extension Node 
    func circle() -> some View 
        Circle()
            .fill(Color(red: red, green: green, blue: blue))
            .frame(width: 64, height: 64, alignment: .center)
            .position(x: x, y: y)
    
    
    func square() -> some View 
        Rectangle()
            .fill(Color(red: red, green: green, blue: blue))
            .frame(width: 64, height: 64, alignment: .center)
            .position(x: x, y: y)
    
    
    @ViewBuilder func drawShape() -> some View 
        switch shape
        case 1: circle()
        case 2: square()
            default: Text("Failed")
        
    
    
    func label() -> some View 
        return Text(text)
            .font(.system(size: 30))
            .bold()
            .position(x: x, y: y)
            .foregroundColor(Color(red: 0.25, green: 0.25, blue: 0.25))
    

节点类:

import Foundation

class Nodes: ObservableObject 
   @Published var n_array: [Node]

    init() 
        let url = Bundle.main.url(forResource: "nodes", withExtension: "json")!
        let data = try! Data(contentsOf: url)
        n_array = try! JSONDecoder().decode([Node].self, from: data)
    

内容视图:

import SwiftUI

struct ContentView: View 
    @ObservedObject var nodes = Nodes()
    
    var body: some View 
        
        ZStack 
            
            ForEach(0..<nodes.n_array.count)  index in
                nodes.n_array[index].drawShape()
                    .gesture(DragGesture()
                        .onChanged  value in
                            nodes.n_array[index].x = value.translation.width
                            nodes.n_array[index].y = value.translation.height
                        
                        .onEnded  value in
                            
                        
                    )
                nodes.n_array[index].label()
            
        
    

【问题讨论】:

【参考方案1】:

嵌套的ObservableObjects 在 SwiftUI 中不起作用,除非您通过调用 objectWillChange 手动将状态传播回父对象。

通常,标准路线是为您的模型使用struct,然后让ObservableObject 父级管理数组。

如果您将模型更改为以下内容,您将看到拖动开始更新:

struct Node: Decodable 
    public let id: Int
    var x: Double
    var y: Double
    public let text: String
    public var red: Double
    public var green: Double
    public var blue: Double
    public var shape: Int

注意:你还需要更多的逻辑来进行拖动,但这超出了这个问题的直接范围——你会在拖动开始时看到项目跳转,因为你需要存储初始翻译

【讨论】:

以上是关于在内容视图 SwiftUI 中更新对象数组的主要内容,如果未能解决你的问题,请参考以下文章

如何切换数组中对象的属性并更新 SwiftUI 视图?

外部模型对象的 SwiftUI 数据流和 UI 更新,其值发生变化但 id 相同

SwiftUI:在数组中更新值后视图没有改变

SwiftUI:如何在另一个视图中更新传递的数组项

Vue.set 向响应式对象中添加响应式属性,及设置数组元素触发视图更新

将对象添加到数组后,tableview 不会更新