首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不更新VIews

不更新VIews
EN

Stack Overflow用户
提问于 2022-09-29 22:15:54
回答 1查看 98关注 0票数 0

总的来说,我对快速编程相当陌生,但我正在尝试构建一个有效的小测验视图,该视图接受JSON文件中的问答问题,并使用自定义的“应答”视图将它们以LazyVGrid模式显示在屏幕上。

这是我的自定义答案视图(很抱歉,测试在所有这些名称上,我有重复的文件来尝试不同的事情而不干扰我的原始文件!):

代码语言:javascript
复制
struct TestAnswerTest: View {
    @State var answer: String
    @State private var selected = false
    var correctAnswers: [String]

    var body: some View {
        Text(answer)
            .font(.title)
            .bold()
            .frame(width: 165, height: 140)
            .contentShape(RoundedRectangle(cornerRadius: 25))
            .onTapGesture {
                self.selected.toggle()
            }
    }
}

我的问题结构:

代码语言:javascript
复制
struct Question2: Codable, Identifiable {
    let id: Int
    let category: String
    let question: String
    let answers: [String]
    let correctAnswers: [String]
    let options: Int
}

我的json数据样本供参考:

代码语言:javascript
复制
{
    "id": 1,
    "category": "staff",
    "question": "What are the 2 common names for the lines and spaces on sheet music?\n(Select 2 answers)",
    "answers": ["Staff", "Stave", "String", "Stem", "Stake", "Store"],
    "correctAnswers": ["Staff", "Stave"],
    "options": 6
}

这是我的小测验显示视图:

代码语言:javascript
复制
struct StaffRecap2: View {
    @State private var questionNumber = 0
    private let twoColumnGrid = [GridItem(.flexible()), GridItem(.flexible())]
    let questions:[Question2] = Bundle.main.decode("questions.json")
    
    var body: some View {
        let staffQuestions = questions.filter { $0.category.elementsEqual("staff")}
        
        NavigationView {
            VStack{
                Text(staffQuestions[questionNumber].question)
                
                LazyVGrid(columns: twoColumnGrid) {
                    ForEach(0..<staffQuestions[questionNumber].options, id:\.self) { number in
                        TestAnswerTest(answer: staffQuestions[questionNumber].answers[number],
                                       correctAnswers: staffQuestions[questionNumber].correctAnswers)
                    }
                    .toolbar {
                        ToolbarItemGroup(placement: .bottomBar) {
                            Button {
                                questionNumber += 1
                                print(staffQuestions[questionNumber])
                            } label: {
                                Text("Next Question")
                            }
                            .disabled(questionNumber == staffQuestions.count)
                        }
                    }
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Gradient(colors: [.teal, .blue]))
            .navigationTitle("Staff Recap")
            .navigationBarTitleDisplayMode(.inline)
            .toolbarBackground(.orange, for: .navigationBar)
            .toolbarBackground(.visible, for: .navigationBar)
        }
    }
}

我的问题是,如果我手动更改"questionNumber“属性和模拟器中的代码构建,并预览所有正确的详细信息,一切似乎都正常,但是如果我使用按钮转到下一个问题,它就会正确地更改问题,但不会更新新的答案选项的任何答案视图。我真的不明白为什么我在应答视图中使用correctAnswers修饰符打印onTapGesture数组,它也为这个问题打印正确的数组,并在我按下按钮时正确地更改。

我有点困惑,我相信这可能是很简单的事情,我错过了,但我陷入了僵局,希望能为我做错的事情找到正确方向的帮助或指点。

提前感谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-10-01 06:25:27

下面是我在评论中提到的方法的一个非常基本的例子,即使用ObservableObject视图模型,在这里执行所有的数据处理。注意,我更新了Question模型和相关的json数据。

代码语言:javascript
复制
import Foundation
import SwiftUI


class QuestionModel: ObservableObject {
    
    @Published var questions:[Question] = []
    
    init() {
        if let loaded: [Question] = Bundle.main.decode("questions.json") {
            questions = loaded
        }
    }
    
    func addAnswer(to n: Int, answer: Answer) {
        questions[n].answers.append(answer)
    }
    
    func removeAnswer(from n: Int, answer: Answer) {
        questions[n].answers.removeAll(where: {$0.id == answer.id})
    }
    
    func isCorrectAnswer(_ n: Int) -> Bool {
        let arr1 = questions[n].correctAnswers.map{$0.id}
        let arr2 = questions[n].answers.map{$0.id}
        let theSet = Set(arr2).subtracting(arr1)
        return theSet.count == 0 && questions[n].correctAnswers.count == questions[n].answers.count
    }
    
}

struct Question: Codable, Identifiable {
    let id: Int
    var category: String
    let question: String
    var answers: [Answer] // <-- the answers from the user
    var possibles: [Answer] // <-- the possible choices of answers
    var correctAnswers: [Answer] // <-- just the correct answers
}

struct Answer: Codable, Identifiable, Hashable {
    let id: Int
    var answer: String
    var isCorrect: Bool
    var answered: Bool
}

struct ContentView: View {
    @StateObject var model = QuestionModel()
    
    @State private var questionNumber = 0
    @State private var showAnswer = false
    private let twoColumnGrid = [GridItem(.flexible()), GridItem(.flexible())]
    
    var body: some View {
        NavigationView {
            ScrollView {
                Text(model.questions[questionNumber].question)
                LazyVGrid(columns: twoColumnGrid) {
                    ForEach($model.questions[questionNumber].possibles) { $answer in
                        AnswerView(questionNumber: $questionNumber, answer: $answer)
                    }
                }
                NavigationLink("", destination: AnswerInfo(questionNumber: questionNumber), isActive: $showAnswer)
            }
            .toolbar {
                ToolbarItemGroup(placement: .bottomBar) {
                    Button {
                        if questionNumber + 1 < model.questions.count {
                            questionNumber += 1
                        }
                    } label: {
                        Text("Next Question").foregroundColor(.black)
                    }
                    Button {
                        showAnswer = true
                    } label: {
                        Text("Check answer").foregroundColor(.black)
                    }
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Gradient(colors: [.teal, .blue]))
        }
        .environmentObject(model)
        .navigationViewStyle(.stack)
        .navigationTitle("Staff Recap")
        .navigationBarTitleDisplayMode(.inline)
    }
}

struct AnswerInfo: View {
    @EnvironmentObject var model: QuestionModel
    @State var questionNumber: Int
    
    var body: some View {
        VStack {
            if model.isCorrectAnswer(questionNumber) {
                Text("Correct answer").font(.title)
            } else {
                Text("NOT correct answer").font(.title)
            }
            ForEach(model.questions[questionNumber].answers) { answer in
                Text(answer.answer)
            }
        }
    }
}

struct AnswerView: View {
    @EnvironmentObject var model: QuestionModel
    
    @Binding var questionNumber: Int
    @Binding var answer: Answer
    
    var body: some View {
        Button {
            answer.answered.toggle()
            if answer.answered {
                model.addAnswer(to: questionNumber, answer: answer)
            } else {
                model.removeAnswer(from: questionNumber, answer: answer)
            }
        } label: {
            Text(answer.answer)
                .font(.title)
                .bold()
                .frame(width: 165, height: 140)
                .contentShape(RoundedRectangle(cornerRadius: 25))
                .foregroundColor(answer.answered ? Color.red : Color.green)
        }
        .buttonStyle(.bordered)
    }
}

extension Bundle {
    func decode<T: Decodable>(_ file: String) -> T? {
        if let url = self.url(forResource: file, withExtension: nil) {
            do {
                let data = try Data(contentsOf: url)
                return try JSONDecoder().decode(T.self, from: data)
            } catch {
                print(error)
            }
        }
        return nil
    }
}

questions.json文件中的json数据

代码语言:javascript
复制
 [
     {
         "id": 1,
         "category": "staff",
         "question": "What are the 2 common names for the lines and spaces on sheet music?\n(Select 2 answers)",
         "answers": [],
         "possibles": [
             {"id": 1, "answer": "Staff", "isCorrect": false, "answered": false},
             {"id": 2, "answer": "Stave", "isCorrect": false, "answered": false},
             {"id": 3, "answer": "String", "isCorrect": false, "answered": false},
             {"id": 4, "answer": "Stem", "isCorrect": false, "answered": false},
             {"id": 5, "answer": "Stake", "isCorrect": false, "answered": false},
             {"id": 6, "answer": "Store", "isCorrect": false, "answered": false},
         ],
         "correctAnswers": [
             {"id": 1, "answer": "Staff", "isCorrect": true, "answered": false},
             {"id": 2, "answer": "Stave", "isCorrect": true, "answered": false}
         ]
     },
     {
         "id": 2,
         "category": "cats",
         "question": "What is this cat?",
         "answers": [],
         "possibles": [
             {"id": 1, "answer": "Cat-1", "isCorrect": false, "answered": false},
             {"id": 2, "answer": "Cat-2", "isCorrect": false, "answered": false},
             {"id": 3, "answer": "Cat-3", "isCorrect": false, "answered": false},
             {"id": 4, "answer": "Cat-4", "isCorrect": false, "answered": false}
         ],
         "correctAnswers": [
             {"id": 2, "answer": "Cat-2", "isCorrect": true, "answered": false}
         ]
     }
 ]
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73902175

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档