如何仅使用 ForEach 而不是 List 从动态范围中删除
Posted
技术标签:
【中文标题】如何仅使用 ForEach 而不是 List 从动态范围中删除【英文标题】:How to delete from dynamic range using only ForEach and not List 【发布时间】:2020-06-15 10:59:24 【问题描述】:我找不到从 ForEach 循环中使用的动态数组中删除的方法。我一直在寻找没有运气。许多答案使用 List 或在其 ForEach 中没有绑定。而且我不想使用列表,因为它很难完全定制它的设计。
以下是从数组中添加和删除元素的示例代码。该数组用于显示玩家的动态列表。
在解开 ForEach 循环中的可选项后,移除一个播放器会产生一个超出范围的索引。
import SwiftUI
struct GameRecapView: View
@State private var game = Game(players: [Player(name: "Steph"),Player(name: "Kim")])
@State private var shape = Shape.circle
var body: some View
VStack
ForEach(self.game.players ,id: \.id) player in
PlayerView(
player: self.$game.players[self.game.players.firstIndex(where: $0.id == player.id)!],
shape: self.$shape)
Spacer()
Button(action:
self.toggleShape()
)
Text("Change shape")
HStack
Button(action:
self.addPlayer(player: Player(name: "Eddye"))
)
Text("+")
Button(action:
self.removeLastPlayer()
)
Text("-")
func toggleShape()
if self.shape == .circle
self.shape = .square
else
self.shape = .circle
func addPlayer(player : Player)
self.game.players.append(player)
func removeLastPlayer()
self.game.players.removeLast()
func removeItems(at offsets: IndexSet)
self.game.players.remove(atOffsets: offsets)
struct PlayerView: View
@Binding var player : Player
@Binding var shape : Shape
var letters = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"]
var body: some View
VStack
ZStack
Text(String(self.player.name.first!.uppercased()))
if shape == .square
Rectangle().stroke().frame(width: 50, height: 50)
else
Circle().stroke().frame(width: 50, height: 50)
Button(action:
self.player.name = self.letters.randomElement()!
)
Text("Change Name")
struct Game
var players : [Player]
struct Player : Identifiable
var id = UUID()
var name : String
enum Shape
case
circle ,
square
struct GameRecapView_Previews: PreviewProvider
static var previews: some View
GameRecapView()
【问题讨论】:
【参考方案1】:看看这个:(测试和工作)
始终致力于单一的事实来源(正如苹果所说的那样),而不是副本。确保您的更改将由 ObservableObject 完成。
class Data : ObservableObject
@Published var game = Game(players: [Player(name: "Steph"),Player(name: "Kim")])
struct GameRecapView: View
@EnvironmentObject var data : Data
@State private var shape = Shape.circle
var body: some View
VStack
ForEach(self.data.game.players ,id: \.id) player in
PlayerView(
player: self.data.game.players[self.data.game.players.firstIndex(where: $0.id == player.id)!],
shape: self.$shape)
Spacer()
Button(action:
self.toggleShape()
)
Text("Change shape")
HStack
Button(action:
self.addPlayer(player: Player(name: "Eddye"))
)
Text("+")
Button(action:
self.removeLastPlayer()
)
Text("-")
func toggleShape()
if self.shape == .circle
self.shape = .square
else
self.shape = .circle
func addPlayer(player : Player)
self.data.game.players.append(player)
func removeLastPlayer()
self.data.game.players.removeLast()
func removeItems(at offsets: IndexSet)
self.data.game.players.remove(atOffsets: offsets)
struct PlayerView: View
@EnvironmentObject var data : Data
var player : Player
@Binding var shape : Shape
var letters = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"]
var body: some View
VStack
ZStack
Text(String(self.player.name.first!.uppercased()))
if shape == .square
Rectangle().stroke().frame(width: 50, height: 50)
else
Circle().stroke().frame(width: 50, height: 50)
Button(action:
let playerIndex = self.data.game.players.firstIndex(where: $0.id == self.player.id)
self.data.game.players[playerIndex!].name = self.letters.randomElement()!
)
Text("Change Name")
struct Game
var players : [Player]
struct Player : Identifiable
var id = UUID()
var name : String
enum Shape
case
circle ,
square
struct ContentView: View
var body : some View
Text("wtf")
struct GameRecapView_Previews: PreviewProvider
static var previews: some View
GameRecapView().environmentObject(Data())
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
【讨论】:
好吧,我会尝试的(我远离计算机,否则我会发疯;)但是为什么我的架构不是基于单一事实来源?哦,是因为 ForEach 枚举了一个游戏副本吗? 是的,它会复制 该死的 SwiftUI 3 个月,今天我明白了......我知道有些不对劲......原来只是我哈哈以上是关于如何仅使用 ForEach 而不是 List 从动态范围中删除的主要内容,如果未能解决你的问题,请参考以下文章
使用 ForEach SwiftUI Core Data 仅更改列表中的一项
我们如何强制 ForEach 使用 UUID 而不是 (id: \.self)?