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
相关产品推荐
相关产品推荐

