【问题标题】:List item is not being updated列表项未更新
【发布时间】:2021-08-02 16:35:04
【问题描述】:

所以我有一个 ViewList 的子视图,它们接受一个对象。这些对象来自我的数据管理器中的数组。

struct ContentView: View {
@ObservedObject var manager = AppConnectivityManager.shared

var body: some View {
    
        List {
            ForEach(manager.goals, id: \.id) { goal in
                let _ = print("goal in foreach: \(goal.goal.completitionCount) + title: \(goal.goal.title)")
                GoalView(goalWrapper:goal)
            }.listRowBackground(Color.clear)
        }
    
    }
}

这部分运行良好,每次更新管理器对象时都会触发更新。

问题是我的GoalView(goalWrapper:goal) 只在代码第一次运行时更新一次,但是当它应该被刷新时它保持不变。目标视图中的 print("progress: 语句始终打印相同的值,但列表中的打印语句获取更新。我可能会错过这个概念,但我可以将ObservedObject 传递到子视图中,并且当manager 也得到更新时它会得到更新,但事实并非如此。

struct GoalView: View {

@ObservedObject var goalWrapper: GoalWrapper

var body: some View {
    let _ = print("progress: \(self.goalWrapper.goal.completitionCount) + daily: \(self.goalWrapper.goal.dailyNotificationCount) + title: \(self.goalWrapper.goal.title)")
    ZStack(content: {
        GoalAnimationView(goalWrapper: self.goalWrapper).cornerRadius(10)
        VStack(alignment: .leading, spacing: nil, content: {
            Text(goalWrapper.goal.title).foregroundColor(.black).padding(.leading, 8)
                .padding(.trailing, 8)
                .padding(.top, 4)
            HStack(alignment: .center,content: {
                Text("\(goalWrapper.goal.completitionCount)/\(goalWrapper.goal.dailyNotificationCount)").padding(.top, 2).padding(.trailing, 85).padding(.bottom, 6)
                Text("\(goalWrapper.goal.completitionCount)").padding(.top, 2).padding(.trailing, 12).padding(.bottom, 12).font(.title)
            }).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0,maxHeight: 35,alignment: .trailing).background(Color.clear)


        }).listRowPlatterColor(Color.blue).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, alignment: .leading).cornerRadius(10)
        
    })
  }
}

这是GoalWrapper

public class GoalWrapper: ObservableObject, Hashable {

    public static func == (lhs: GoalWrapper, rhs: GoalWrapper) -> Bool {
        return lhs.goal.id == rhs.goal.id
    }

    public func hash(into hasher: inout Hasher) {
         hasher.combine(goal.id)
    }

    @Published var goal: Goal!
    let id: String
    init(goal: Goal) {
        self.goal = goal
        self.id = goal.id
   }
}

有什么方法可以将更新传递给列表子视图?我发现其他一些人对列表有问题并将绑定传递给列表中的视图。这是唯一的方法吗?

【问题讨论】:

  • 摆脱你的包装,把你的Goal作为struct传递(我希望它是struct)。

标签: swiftui combine swiftui-list


【解决方案1】:

您不需要GoalWrapper。您应该将goal 作为Binding<Goal>ContentView 传递到GoalView

如果您在ForEach 所在的位置收到警告,则说明您在Goal 上拥有id 属性,但可能需要符合Identifiable 协议。否则将, id: \.id 添加回来。

代码:

struct ContentView: View {
    @ObservedObject var manager = AppConnectivityManager.shared

    var body: some View {
        List {
            ForEach($manager.goals) { $goal in
                let _ = print("goal in foreach: \(goal.completitionCount) + title: \(goal.title)")
                GoalView(goal: $goal)
            }.listRowBackground(Color.clear)
        }
    }
}
struct GoalView: View {
    @Binding var goal: Goal

    var body: some View {
        let _ = print("progress: \(goal.completitionCount) + daily: \(goal.dailyNotificationCount) + title: \(goal.title)")
        ZStack(content: {
            //GoalAnimationView(goalWrapper: self.goalWrapper).cornerRadius(10) // This needs changing too
            VStack(alignment: .leading, spacing: nil, content: {
                Text(goal.title).foregroundColor(.black).padding(.leading, 8)
                    .padding(.trailing, 8)
                    .padding(.top, 4)
                HStack(alignment: .center,content: {
                    Text("\(goal.completitionCount)/\(goal.dailyNotificationCount)").padding(.top, 2).padding(.trailing, 85).padding(.bottom, 6)
                    Text("\(goal.completitionCount)").padding(.top, 2).padding(.trailing, 12).padding(.bottom, 12).font(.title)
                }).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0,maxHeight: 35,alignment: .trailing).background(Color.clear)


            }).listRowPlatterColor(Color.blue).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, alignment: .leading).cornerRadius(10)

        })
    }
}

【讨论】:

  • 由于某种原因,我无法将绑定直接传递给 for each 所以我做了这个解决方法ForEach((0...manager.normalGoals.count - 1), id: \.self) {} 然后只是GoalView(goal: $manager.normalGoals[$0])
  • @beowulf 它是 Swift 5.5 的一部分,我相信 Xcode 13。按索引执行此操作的方式应该没问题,但请务必将范围更改为 0 ..< manager.normalGoals.count,否则应用程序将崩溃如果数组为空,因为它会创建一个无效的范围。
  • @beowulf Here 是一篇关于新语法的文章,以及如何使它与旧版本的 Swift 一起工作(就像你所做的那样)。不依赖于操作系统版本。另外,如果您发现答案有用,我们将不胜感激!
  • 如果我想从数组中删除项目并刷新列表,您是否知道是否有一些技巧?到目前为止,它因索引超出范围而崩溃。我猜是因为它在迭代时被移除了。
  • @beowulf 查看我的回答here。尝试该答案的Binding<Color>(...) 部分,这应该可以解决它。如果这不起作用,请随时发布新问题。
猜你喜欢
  • 2021-11-13
  • 2013-03-02
  • 1970-01-01
  • 2021-10-23
  • 1970-01-01
  • 1970-01-01
  • 2018-12-06
  • 1970-01-01
  • 2010-12-07
相关资源
最近更新 更多