SwiftUI实现选择题仅加载新题目时打乱答题选项
解决Trivia API选项重复打乱的问题
你当前的问题在于每次用户选择答案后,视图状态变化触发重绘,而ForEach里直接调用shuffleAnswers()会导致每次重绘都重新打乱选项。要实现仅加载新题时打乱选项,需要把打乱后的选项存储为状态变量,只在切换题目时更新它。
修改步骤:
- 添加状态变量存储当前题目的打乱选项
在你的View结构体中添加一个@State变量,用来保存当前题目的已打乱选项:
@State private var currentShuffledAnswers: [String] = []
- 重构选项打乱逻辑,仅在加载新题时执行
创建一个专门加载并打乱当前题目选项的方法,替换原来的shuffleAnswers():
func loadCurrentQuestionAnswers() { guard !api.QnAData.isEmpty, currentQuestionIndex < api.QnAData.count else { currentShuffledAnswers = [] return } let currentQuestion = api.QnAData[currentQuestionIndex] var answers = currentQuestion.incorrectAnswers answers.append(currentQuestion.correctAnswer) // 解码并打乱选项,结果存入状态变量 currentShuffledAnswers = answers.compactMap { $0.removingPercentEncoding }.shuffled() }
- 在合适时机触发选项加载
- 视图首次出现时加载初始题目选项:
.onAppear { loadCurrentQuestionAnswers() }
- 点击「Next」按钮切换题目后,重新加载新题的打乱选项:
Button("Next") { currentQuestionIndex += 1 // 重置答题状态 answerSelected = nil hasUserAnswered = false // 加载新题的打乱选项 loadCurrentQuestionAnswers() } .disabled(!hasUserAnswered) // 保持原有的未答题不可点击逻辑
- 修改ForEach遍历状态变量
把原来ForEach(shuffleAnswers(), id: \.self)改成遍历存储好的currentShuffledAnswers,避免每次重绘都重新打乱:
if !api.QnAData.isEmpty { ForEach(currentShuffledAnswers, id: \.self) { shuffledAnswer in Button(action: { guard answerSelected == nil else { return } let decodedAnswer = shuffledAnswer.removingPercentEncoding ?? shuffledAnswer answerSelected = decodedAnswer hasUserAnswered = true // 判断答案是否正确并更新得分 let correctAnswer = api.QnAData[currentQuestionIndex].correctAnswer.removingPercentEncoding ?? api.QnAData[currentQuestionIndex].correctAnswer if decodedAnswer == correctAnswer { score += 1 print("答对了,当前得分:\(score)") } else { print("答错了,当前得分:\(score)") } }) { Text(shuffledAnswer) // 保留你原有的按钮样式代码 } } }
为什么原来的写法会出问题?
SwiftUI是状态驱动的视图框架,当answerSelected、hasUserAnswered这类状态变量变化时,整个View会重新渲染。原来在ForEach里直接调用shuffleAnswers(),相当于每次渲染都执行一次打乱逻辑,所以用户选完答案后状态变化触发重绘,选项就被重新打乱了。
内容的提问来源于stack exchange,提问作者AranAli
相关产品推荐
相关产品推荐

