属性更改后在 SwiftUI 中更新列表

Posted

技术标签:

【中文标题】属性更改后在 SwiftUI 中更新列表【英文标题】:Updating Lists in SwiftUI after property changes 【发布时间】:2020-11-20 08:58:52 【问题描述】:

我的程序有两个主要类,TeamPlayer。 Team 有一个内置数组,其中包含 Player 类的 23 个实例,所有实例都有自己的属性和方法。在我的应用程序的主要内容视图中,我显示了这些 homeTeam.players 的列表,并且每一行都有一个 .contextMenu 可以选择调用 editName() 来自单个玩家。

editName() 被调用时,它将打开一个警报并允许用户在 textField 中输入一个新名称,然后保存它并更改 Player 的 name 属性。

我的问题是列表不会在主视图上更新并且玩家名称保持不变,但是当您再次更改它时,名称就在 textField 中,所以它已经改变了,只是'没有被显示。

玩家等级:

    class Player
        var playerName: String = ""
        var id = UUID()

        init(playerName: String)
             self.playerName = playerName
        

        func editName
            //Displays alert with text field
            self.playerName = newName
        
    

团队班:

    class Team
        var teamName: String = ""
        var players: [Player] = [Player("Player 1"),
                                 Player("Player 2"),
                                 Player("Player 3"),
                                 Player("Player 4")] //Continues for 23 Players

        init(teamName: String)
             self.teamName = teamName
        

    

快速视图:

    List(homeTeam.players) player in
        HStack
            Text("\(player.shirtNumber) - \(player.playerName)")
            Spacer()
            Text("\(player.timerText)")
        
        .contextMenu
            Button(action: player.editName()) 
                Text("Edit Name")
                Image(systemName: "square.and.pencil")
                                
        
    

我对 SwiftUI 还是比较陌生,但对 UIKit 和故事板有一定的经验,因此我们将不胜感激。

【问题讨论】:

使您的模型结构并添加视图模型作为 ObservableObject 持有您的模型作为发布的属性。 将播放器类更改为结构?团队也是?然后我将什么更改为 ObservableObject?抱歉,这方面经验不是很丰富 【参考方案1】:

这是可能的方式(未测试,内联输入)

struct Player: Identifiable 
    var playerName: String = ""
    var id = UUID()

    init(playerName: String)
         self.playerName = playerName
    

    mutable func editName
        //Displays alert with text field
        self.playerName = newName
    


struct Team
    var teamName: String = ""
    var players: [Player] = [Player("Player 1"),
                             Player("Player 2"),
                             Player("Player 3"),
                             Player("Player 4")] //Continues for 23 Players

    init(teamName: String)
         self.teamName = teamName
    

现在将模型视为

class ViewModel: ObservableObject 
   @Published var homeTeam = Team()


and updated view

struct ContentView: View 
   @StateObject var vm = ViewModel()

   var body: some View 
    List(Array(vm.homeTeam.players.enumerated()), id: \.1)  (index, player) in
        HStack
            Text("\(player.shirtNumber) - \(player.playerName)")
            Spacer()
            Text("\(player.timerText)")
        
        .contextMenu
            Button(action: vm.homeTeam.players[i].editName()) 
                Text("Edit Name")
                Image(systemName: "square.and.pencil")
                                
        
    
   

【讨论】:

在一个空视图上测试它,它就像我想要的那样工作;当我尝试将它实施到我的项目中时,我在此代码上收到错误“转义闭包捕获变异'self'参数”:let enter = UIAlertAction(title: "Enter", style: .default) (_) in self.playerName = alert.textFields![0].text! 任何想法? 你应该只通过视图模型更新模型,因为模型现在是值类型。 您如何建议让用户输入一个新名称,而不像我目前使用的那样使用 textView 和警报?【参考方案2】: 将 Team 的一致性添加到 ObservableObject 确保 homeTeam 标记为 @ObservedObject var homeTeam: Team 当需要编辑玩家的名字时,调用一个(新的)方法 Team,而不是 Player,可能命名为 changeName(player: Player, to newName: String) 为您进行更改 确保 changeName() 调用 Team 方法 objectWillChange.send() 所以视图知道团队已经改变 (此方法是 ObservedObject 协议的一部分)。就是这样 导致视图重绘。

来自 HackingWithSwift (@delawaremathguy) 的回答 - https://www.hackingwithswift.com/forums/swiftui/updating-lists-in-swiftui-after-property-changes/4910

【讨论】:

以上是关于属性更改后在 SwiftUI 中更新列表的主要内容,如果未能解决你的问题,请参考以下文章

属性更改时 Observable 不更新列表

在 SwiftUI 中创建一个包含自定义类数组的列表

如何让 TextField 值更改触发 SwiftUI 中另一条数据的更新?

POST 请求后在 swift 模型中访问值的问题

Swift UI - EnvironmentObject 更改不会更新 UI

删除嵌套属性中的元素时更新 SwiftUI 列表