0

我有一个关于 Swift 的问题,我无法理解。我有一个很简单的看法。这是一个列表,您可以在其中写下每个玩家的姓名,一旦您点击返回,名称就会通过onCommit附加到数组playerArray中。到目前为止,这工作正常。

现在我想将此数组中的名称传递给另一个视图。我怎么做?我是否使用@EnvironmentObject,是否将其保存到@AppStorage或者我需要使用/保存到Core Data然后在我需要的视图中获取数据?

在下一个视图中,我想先显示玩家 1 的姓名,然后在他完成游戏后显示玩家 2 的姓名,当他完成游戏后,再显示玩家 3 的姓名,依此类推。当每个人都玩游戏时,我需要所有的名字再次用于记分牌。在写下来的时候,我想我还需要一种方法来将每个玩家的得分与名字绑定。

稍后我还希望有两支球队,每支球队有两名或更多球员。那里的顺序是A队,玩家1;B队,球员1;A队,选手2;B队,玩家2等等。

任何关于如何使这成为可能的提示都会很棒。如果我需要使用 Core Data 来正确执行此操作,那么我将深入研究 Core Data。

谢谢!

https://i.stack.imgur.com/EgJ3p.gif

import SwiftUI

struct ContentView: View {
    
    @State var playerField = ""
    @State var playerArray: [String] = []
    
    var body: some View {
        
        VStack {
            List {
                
                ForEach(playerArray, id: \.self) { data in
                    Text(data)
                }
                
                TextField(
                    "Name",
                    text: $playerField,
                    onCommit: {
                        playerArray.append(playerField)
                        playerField = ""
                    }
                )
                
            } // List
        } // VStack
        
        
    } // some View
} // ContentView: View

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
4

1 回答 1

0

这是一个有点简单的解决方案,它以一个相当大的结尾,ContentView但你会明白的:

struct ContentView: View {

    enum GameState {
        case onboarding
        case running
        case done
    }

    // Shared across views
    @State var gameState = GameState.onboarding
    @State var playerArray: [String] = []

    @State var playerField = ""     // only used in player onboarding

    @State var currentPlayerIdx = 0 // only used while game is running

    var body: some View {
        if case .onboarding = gameState {
            // Player onboarding view (should be an independent view)
            VStack {
                List {

                    ForEach(playerArray, id: \.self) { data in
                        Text(data)
                    }

                    TextField(
                        "Name",
                        text: $playerField,
                        onCommit: {
                            playerArray.append(playerField)
                            playerField = ""
                        }
                    )

                } // List

                Button("Start game") {
                    gameState = .running
                }
                .disabled(playerArray.isEmpty)
            } // VStack Player onboarding view

        } else if case .running = gameState {
            // Game view (should be an independent view)
            VStack {
                Text("\(playerArray[currentPlayerIdx])'s turn")
                    .font(.headline)

                Button("Finish move") {
                    currentPlayerIdx += 1
                    if currentPlayerIdx == playerArray.count {
                        currentPlayerIdx = 0
                    }
                }
                .padding()

                Button("End game") {
                    gameState = .done
                }
            } // VStack Game view
            .padding()

        } else if case .done = gameState {
            // Finished view (should be its own view)
            VStack {
                Button("Start again") {
                    gameState = .onboarding
                }
            } // VStack Game view
        }
    } // some View
} // ContentView: View

我添加了一个GameState枚举来区分游戏阶段(入职、运行、完成)。更新此枚举时,主体将生成一个不同的视图,显示给用户。

您会看到以下问题:基本上ContentView,三个不同屏幕的逻辑和视图布局。某些@State变量仅在子屏幕中需要。只有gameStateandplayerArray用于多个屏幕。

合乎逻辑的下一步是重构代码并ContentView根据gameState. 例如,PlayerOnboadingView我们将传递“共享状态”(gameStateplayerArray)作为绑定以允许对其进行修改。

struct PlayerOnboardingView: View {
    @Binding var gameState: ContentView.GameState
    @Binding var playerArray: [String]

    @State var playerField = ""     // only used in player onboarding

    var body: some View {
        VStack {
            List {
                ForEach(playerArray, id: \.self) { data in
                    Text(data)
                }

                TextField(
                    "Name",
                    text: $playerField,
                    onCommit: {
                        playerArray.append(playerField)
                        playerField = ""
                    }
                )

            } // List

            Button("Start game") {
                gameState = .running
            }
            .disabled(playerArray.isEmpty)
        } // VStack Player onboarding view
    }
}

ContentView您将当前替换VStack

// Player onboarding view
PlayerOnboardingView(gameState: $gameState, playerArray: $playerArray)

playerField并且您从中删除未使用的状态变量ContentView

对其他子视图也可以这样做:创建 aGameRunningView和 a GameFinishedView

于 2022-02-04T08:47:53.403 回答