SwiftUI:如何在Quiz中选择每个玩家的问题数量?

kpbpu008  于 2023-04-10  发布在  Swift
关注(0)|答案(1)|浏览(107)

我是相当新的SwiftUI,并试图建立一个测验应用程序。我已经有可能添加球员,并选择您想要的类别..现在我希望用户有选择的问题数量为每个用户的游戏会话(10个问题/用户为例)。我会尝试摆弄它自己,但不知道从哪里开始。

**编辑:**抱歉,我知道我不清楚我在寻求帮助。我需要一些帮助,如何根据用户选择的问题数量来过滤问题。我的想法是,用户可以通过选择器选择5,10,15或20,这应该反映出每个用户将在测验中回答多少问题。如果我没有显示足够的代码,我只是不确定我应该包括什么。

以下是我到目前为止的简单观点:

struct NumberSelectionView: View {
    @EnvironmentObject var viewModel: GameVM

    enum Questions: Int, CaseIterable, Identifiable {
        case five = 5
        case ten = 10
        case fifteen = 15
        case twenty = 20

        var id: Int { self.rawValue }
    }
    
    @State private var selectedOption = Questions.five
    
    var body: some View {
        VStack {
            Spacer()
            
            VStack(spacing: 0) {
                Text("\(selectedOption.rawValue) questions")
                    .font(.system(size: 40, weight: .bold, design: .rounded))
                    .foregroundColor(Color(UIColor.systemBlue))
                    .multilineTextAlignment(.center)
                Text("per player")
                    .font(.system(size: 40, weight: .bold, design: .rounded))
            }
            Picker("Select number of questions", selection: $selectedOption) {
                Text("\(5)").tag(Questions.five)
                Text("\(10)").tag(Questions.ten)
                Text("\(15)").tag(Questions.fifteen)
                Text("\(20)").tag(Questions.twenty)
            }
            .pickerStyle(WheelPickerStyle())
            
            Spacer()
            
            NavigationLink(
                destination: GameView(),
                label: {
                    PrimaryButton(text: "Continue")
                }
            )
        }
        .padding()
        .navigationTitle("Number of questions")
        .navigationBarTitleDisplayMode(.inline)
    }
}

下面是我的ViewModel的一部分:

// Filter questions based on active categories
    var filteredQuestions: [QuestionModel] {
        let filteredCategoryNames = categories
            .filter(\.isActive) // filters for the active categories
            .map(\.name) // turns it into an array containing the name of each category

        return questions.filter { question in
           filteredCategoryNames.contains(question.category)
        }
    }
    
    // Get question title for current question
    var questionTitle: String {
        game.currentQuestion.question
    }
    
    // Get category for current question
    var questionCategory: String {
        game.currentQuestion.category
    }
    
    // Get options for current question
    var optionIndices: Range<Int> {
        game.currentQuestion.options.indices
    }
    
    // Get text for each option for current question
    func optionText(for index: Int) -> String {
        game.currentQuestion.options[index]
    }

以下是我的GameView的一部分:

var body: some View {
        VStack(spacing: 16) {
            Spacer()
            VStack(spacing: 16) {
                CategoryTagView(name: viewModel.questionCategory, iconSize: 20, textSize: 16)
                QuestionTitleView(text: viewModel.questionTitle, size: 32)
            }
            .padding(.horizontal, 16)
            Spacer()
            LazyVGrid(columns: columns, spacing: 8) {
                ForEach(viewModel.optionIndices) { index in
                    VStack(spacing: 16) {
                        OptionIconView(index: index)
                        Text(viewModel.optionText(for: index))
                            .fixedSize(horizontal: false, vertical: true)
                            .font(.system(size: 16, weight: .bold, design: .rounded))
                            .frame(maxWidth: .infinity)
                            .multilineTextAlignment(.center)
                    }
                    .frame(maxWidth: .infinity, minHeight: 120)
                    .padding(8)
                    .background(viewModel.colorForOption(at: index))
                    .cornerRadius(24)
                    .onTapGesture {
                        viewModel.guessMadeForCurrentQuestion(at: index)
                        viewModel.calculateScore(at: index)
                        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                            viewModel.nextQuestion()
                        }
                    }
                    .disabled(viewModel.verifyGuess)
                    
                }
            }
            .padding()
        }
...
}
mzsu5hc0

mzsu5hc01#

以下是重写并修复的代码:

struct NumberSelectionView: View {
        @EnvironmentObject var viewModel: GameVM
    
        enum Questions: Int, CaseIterable, Identifiable {
            case five = 5
            case ten = 10
            case fifteen = 15
            case twenty = 20
    
            var id: Int { self.rawValue }
        }
    
        @State private var selectedOption = Questions.five
    
        var body: some View {
            VStack {
                Spacer()
    
                VStack(spacing: 0) {
                    Text("\(selectedOption.rawValue) questions")
                        .font(.system(size: 40, weight: .bold, design: .rounded))
                        .foregroundColor(Color(UIColor.systemBlue))
                        .multilineTextAlignment(.center)
                    Text("per player")
                        .font(.system(size: 40, weight: .bold, design: .rounded))
                }
                Picker("Select number of questions", selection: $selectedOption) {
                    Text("\(5)").tag(Questions.five)
                    Text("\(10)").tag(Questions.ten)
                    Text("\(15)").tag(Questions.fifteen)
                    Text("\(20)").tag(Questions.twenty)
                }
                .pickerStyle(WheelPickerStyle())
    
                Spacer()
    
                NavigationLink(
                    destination: GameView(numberOfQuestions: selectedOption.rawValue),
                    label: {
                        PrimaryButton(text: "Continue")
                    }
                )
            }
            .padding()
            .navigationTitle("Number of questions")
            .navigationBarTitleDisplayMode(.inline)
        }
    }
    
    class GameVM: ObservableObject {
        @Published var players: [PlayerModel]
        var categories: [CategoryModel]
        var questions: [QuestionModel]
        var numberOfQuestions: Int // added property to keep track of the number of questions
        var currentQuestionIndex: Int = 0
        var currentQuestion: QuestionModel {
            questions[currentQuestionIndex]
        }
    
        init(players: [PlayerModel], categories: [CategoryModel], questions: [QuestionModel], numberOfQuestions: Int) {
            self.players = players
            self.categories = categories
            self.questions = questions
            self.numberOfQuestions = numberOfQuestions // initialize the numberOfQuestions property
        }
    
        var filteredQuestions: [QuestionModel] {
            let filteredCategoryNames = categories
                .filter(\.isActive)
                .map(\.name)
    
            return questions
                .filter { question in
                    filteredCategoryNames.contains(question.category)
                }
                .prefix(numberOfQuestions) // filter by the selected number of questions
                .shuffled() // optional: shuffle the questions
        }
    
        // rest of the properties and methods remain the same
    }
    struct GameView: View {
        @EnvironmentObject var viewModel: GameVM
        let numberOfQuestions: Int
    
        var body: some View {
            VStack(spacing: 16) {
                Spacer()
                VStack(spacing: 16) {
                    CategoryTagView(name: viewModel.currentQuestion.category, iconSize: 20, textSize: 16)
                    QuestionTitleView(text: viewModel.currentQuestion.title, size: 32)
                }
                .padding(.horizontal, 16)
                Spacer()
                LazyVGrid(columns: columns, spacing: 8) {
                    ForEach(viewModel.optionIndices) { index in
                        VStack(spacing: 16) {
                            OptionIconView(index: index)
                            Text(viewModel.optionText(for: index))
                                .fixedSize(horizontal: false, vertical: true)
                                .font(.system(size: 16, weight: .bold, design: .rounded))
                                .multilineTextAlignment(.center)
                        }
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .background(viewModel.optionBackgroundColor(for: index))
                        .cornerRadius(16)
                        .onTapGesture {
                            viewModel.selectOption(at: index)
                        }
                    }
                }
                Spacer()
                PrimaryButton(text: viewModel.buttonText, action: viewModel.submitAnswer)
            }
            .padding()
            .navigationTitle(viewModel.navigationTitle)
            .navigationBarTitleDisplayMode(.inline)
            .alert(item: $viewModel.alertItem) { alertItem in
                Alert(title: alertItem.title, message: alertItem.message, dismissButton: alertItem.dismissButton)
            }
            .onAppear {
                viewModel.prepareGame(with: numberOfQuestions)
            }
        }
    
        private let columns = [
            GridItem(.adaptive(minimum: 150), spacing: 16)
        ]
    }

相关问题