【问题标题】:How to delete from dynamic range using only ForEach and not List如何仅使用 ForEach 而不是 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()
    }
}

【问题讨论】:

    标签: foreach swiftui


    【解决方案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 个月,今天我明白了......我知道有些不对劲......原来只是我哈哈
    猜你喜欢
    • 1970-01-01
    • 2017-03-18
    • 1970-01-01
    • 2020-02-14
    • 1970-01-01
    • 2013-10-07
    • 2013-04-19
    • 1970-01-01
    • 2021-12-19
    相关资源
    最近更新 更多