You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI问答应用:答案随机洗牌功能实现求助

解决SwiftUI问答应用答案随机洗牌问题

核心问题分析

你当前的shuffleAnswers()函数仅生成了打乱后的答案数组,但未将其存储为UI可读取的状态,且界面仍在分别渲染错误答案和正确答案,完全没有用到洗牌后的结果。

具体修改方案

1. 添加状态变量存储打乱后的答案

在QuizGameScreen中新增@State变量,用于保存当前问题的所有打乱后的答案(复用你已定义的Answer结构体,它符合Identifiable协议,适配SwiftUI的ForEach组件):

@State private var shuffledAnswers: [Answer] = []

2. 重写shuffleAnswers()函数

调整函数逻辑,将正确答案和错误答案包装为Answer实例,合并后打乱并赋值给状态变量:

func shuffleAnswers() {
    guard currentQuestionIndex < api.QnAData.count else { return }
    
    let currentQuestion = api.QnAData[currentQuestionIndex]
    
    // 创建正确答案实例
    let correctAnswer = Answer(
        text: currentQuestion.correctAnswer.removingPercentEncoding ?? currentQuestion.correctAnswer,
        isCorrect: true
    )
    
    // 创建错误答案实例数组
    let incorrectAnswers = currentQuestion.incorrectAnswers.map { answerText in
        Answer(
            text: answerText.removingPercentEncoding ?? answerText,
            isCorrect: false
        )
    }
    
    // 合并并打乱数组
    shuffledAnswers = (incorrectAnswers + [correctAnswer]).shuffled()
}

3. 触发洗牌的时机

除了数据加载完成后调用洗牌函数,还需在切换题目时重新洗牌,通过.onChange修饰符监听currentQuestionIndex的变化:
在ZStack末尾添加:

.onChange(of: currentQuestionIndex) { _ in
    shuffleAnswers()
}

4. 修改UI渲染逻辑

替换原有的错误答案循环和正确答案按钮,改为遍历shuffledAnswers数组统一渲染答案按钮:

ForEach(shuffledAnswers) { answer in
    Button(action: {
        if answer.isCorrect {
            print("correct answer")
        } else {
            print("wrong answer")
        }
    }) {
        Text(answer.text)
            .font(.system(size: 20, design: .rounded))
            .foregroundColor(.purple)
            .frame(width: 300, alignment: .leading)
            .padding()
            .background(Color.white)
            .fontWeight(.bold)
            .cornerRadius(10)
    }
}

5. 优化数据加载后的调用

确保数据加载完成后调用洗牌函数,同时处理初始空数据状态:
在.task闭包内的try await api.getQnAData(...)之后添加:

if !api.QnAData.isEmpty {
    shuffleAnswers()
}

完整修改后的QuizGameScreen代码

import Foundation
import SwiftUI

struct QuizGameScreen: View {
    
    @StateObject var api = TriviaAPI()
    @Binding var selectedCategoryNumber: Int
    @Binding var selectedCategoryName: String
    @State var currentQuestionIndex = 0
    @Binding var selectedDifficultyInPopup: String
    @State private var shuffledAnswers: [Answer] = [] // 新增状态变量
    
    func shuffleAnswers() {
        guard currentQuestionIndex < api.QnAData.count else { return }
        
        let currentQuestion = api.QnAData[currentQuestionIndex]
        
        // 创建正确答案实例
        let correctAnswer = Answer(
            text: currentQuestion.correctAnswer.removingPercentEncoding ?? currentQuestion.correctAnswer,
            isCorrect: true
        )
        
        // 创建错误答案实例数组
        let incorrectAnswers = currentQuestion.incorrectAnswers.map { answerText in
            Answer(
                text: answerText.removingPercentEncoding ?? answerText,
                isCorrect: false
            )
        }
        
        // 合并并打乱数组
        shuffledAnswers = (incorrectAnswers + [correctAnswer]).shuffled()
    }
    
    var body: some View {
    
        ZStack{
            
            Image("NewBgQuizUp")
                .resizable()
                .scaledToFill()
                .edgesIgnoringSafeArea(.all)
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight:.infinity)
            
            VStack(alignment: .leading){
                Text("QuizUp")
                    .font(.system(size: 36, design: .rounded))
                    .fontWeight(.bold)
                    .foregroundColor(.white)
                    .offset(x: -100, y: -350)
            }
            
            Text("\(currentQuestionIndex + 1) out of \(api.QnAData.count)") // 动态显示题目计数
                .font(.system(size: 23, design: .rounded))
                .fontWeight(.bold)
                .foregroundColor(.white)
                .offset(x: 100, y: -300)
            
            VStack{
            
                if !api.QnAData.isEmpty {
                    if currentQuestionIndex < api.QnAData.count {
                        if let decodedQuestion = api.QnAData[currentQuestionIndex].question.removingPercentEncoding {
                            Text(decodedQuestion)
                                .font(.system(size: 23, design: .rounded))
                                .fontWeight(.bold)
                                .foregroundColor(.white)
                                .offset(y: -100)
                                .multilineTextAlignment(.center)
                                .padding(.horizontal)
                        } else {
                            Text("Failed to decode question")
                                .font(.system(size: 23, design: .rounded))
                                .fontWeight(.bold)
                                .foregroundColor(.white)
                                .offset(y: -100)
                        }

                        // 遍历打乱后的答案数组
                        ForEach(shuffledAnswers) { answer in
                            Button(action: {
                                if answer.isCorrect {
                                    print("correct answer")
                                } else {
                                    print("wrong answer")
                                }
                            }) {
                                Text(answer.text)
                                    .font(.system(size: 20, design: .rounded))
                                    .foregroundColor(.purple)
                                    .frame(width: 300, alignment: .leading)
                                    .padding()
                                    .background(Color.white)
                                    .fontWeight(.bold)
                                    .cornerRadius(10)
                            }
                            .padding(.vertical, 5)
                        }
                    }
                } else {
                    Text("Loading...")
                        .font(.system(size: 23, design: .rounded))
                        .fontWeight(.bold)
                        .foregroundColor(.white)
                        .offset(y: -100)
                }
            }
        }
        .task {
            do {
                try await api.getQnAData(selectedCategoryNumber: selectedCategoryNumber, selectedDifficultyInPopup: selectedDifficultyInPopup)
                if !api.QnAData.isEmpty {
                    shuffleAnswers()
                }
            } catch APIErrors.invalidData {
                print("Invalid Data")
            } catch APIErrors.invalidURL {
                print("Invalid Url")
            } catch APIErrors.invalidResponse {
                print("Invalid Response")
            } catch {
                print("General error")
            }
        }
        .onChange(of: currentQuestionIndex) { _ in
            shuffleAnswers()
        }
    }
}

struct QuizGameScreen_Previews: PreviewProvider {
    static var previews: some View {
        QuizGameScreen(selectedCategoryNumber: .constant(21), selectedCategoryName: .constant("Sport"), selectedDifficultyInPopup: .constant("Easy"))
    }
}

enum APIErrors: Error {
    case invalidURL
    case invalidResponse
    case invalidData
}

额外优化点

  • 修正题目计数文本,动态显示当前题目序号和总题数
  • 给题目文本添加居中对齐和水平内边距,优化长题目显示效果
  • 给答案按钮添加垂直间距,提升界面视觉舒适度

内容的提问来源于stack exchange,提问作者AranAli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:54:55