属性更改后在 SwiftUI 中更新列表
Posted
技术标签:
【中文标题】属性更改后在 SwiftUI 中更新列表【英文标题】:Updating Lists in SwiftUI after property changes 【发布时间】:2020-11-20 08:58:52 【问题描述】:我的程序有两个主要类,Team 和 Player。 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 中更新列表的主要内容,如果未能解决你的问题,请参考以下文章
如何让 TextField 值更改触发 SwiftUI 中另一条数据的更新?