Home > Software engineering >  Referring to a json array file for swiftui
Referring to a json array file for swiftui

Time:04-05

I am trying to write code so that each time the confirm answer button is clicked, the next question in the json array is called. There are five questions in this file and so far I can get the first and second question to appear. Is there anyway I could write a loop so that the next question is called each time the user enters confirm? I am new to swiftui and so am unsure about how to proceed

import SwiftUI
struct SecondView: View {

var ResearchMCQ: Question


//Creating Variables for Revision Topics
@State private var setOptionOne = false
@State private var setOptionTwo = false
@State private var setOptionThree = false
    
let button = ["Confirm Answer"]
@State public var buttonConfirm: Int?

        var body: some View {

        ScrollView{
            
            VStack(spacing: 1.0) {
   
 Group {
    Text(ResearchMCQ.question)
    .padding(.trailing, 5)
    

//Ensures Only One Answer Can Be Selected
        let OptionOne = Binding<Bool>(get: { self.setOptionOne }, set: { self.setOptionOne = $0; self.setOptionTwo = false; self.setOptionThree = false })
        let OptionTwo = Binding<Bool>(get: { self.setOptionTwo }, set: { self.setOptionOne = false; self.setOptionTwo = $0; self.setOptionThree = false })
        let OptionThree = Binding<Bool>(get: { self.setOptionThree }, set: { self.setOptionOne = false; self.setOptionTwo = false; self.setOptionThree = $0 })


        VStack {
            Toggle(ResearchMCQ.options[0], isOn: OptionOne)
                .toggleStyle(.button)
                .tint(Color(.gray))
                .foregroundColor(Color("Black-White"))
            Toggle(ResearchMCQ.options[1], isOn: OptionTwo)
                .toggleStyle(.button)
                .tint(Color(.gray))
                .foregroundColor(Color("Black-White"))
            Toggle(ResearchMCQ.options[2], isOn: OptionThree)
                .toggleStyle(.button)
                .tint(Color(.gray))
                .foregroundColor(Color("Black-White"))
                 }
    }
                
                Spacer()
                Spacer()
                
                HStack(spacing: 15) {
                ForEach(0..<button.count, id: \.self) {button in
                        Button(action: {
                            self.buttonConfirm = button
                            
                        }) {
                            
    //Links Continue Button To Next Page
                            NavigationLink(destination: SecondView(ResearchMCQ: questions[1])) {
                                Text("Confirm Answer")
                                
                            }
                            
                            .padding(.vertical, 12.5)
                            .padding(.horizontal, 120)
                            .foregroundColor(.white)
                            .foregroundStyle(.background)
                            .background(2 == button ? Color.primary: Color.secondary)
                            .clipShape(Capsule())
                    
                    
                }
                
                
        }
    }
}
            

   .navigationTitle("")
            
        }

}

        }


struct SecondView_Previews: PreviewProvider {
static var previews: some View {
    SecondView(ResearchMCQ: questions[0])

}

}

CodePudding user response:

If all questions have a similar structure, there are a couple of ways to achieve that.

For example, in the parent view you can iterate through the array of questions and call each time SecondView with a different question. I recommend that approach.

Because you didn't provide the parent view code, I propose here below a way to iterate through the array directly in SecondView.

You can change the same view instead of navigating to another one. So, SecondView should hold all questions, not just one, and you change the index of the question you are showing.

The steps to follow are here below:

  1. Have your view holding the whole array of questions and not only one question. By the way, in Swift variables are lower caps.
// Remember to pass the whole array of questions to this variable
let researchMCQ: [Question]
  1. Have another variable to hold the current question.
@State private var questionIndex = 0
  1. Also buttonConfirm should be an array in this case.
@State public var buttonConfirm = [Int?]()
  1. Show the current question (see how the variable researchMCQ is used here).
 Group {
    Text(researchMCQ[questionIndex].question)
    .padding(.trailing, 5)
  1. The confirmation button doesn't need a NavigationLink, just change the index and the next question will be shown.
Button {
    buttonConfirm[questionIndex] = button

    // Make sure the index doesn't go beyond the array size
    if researchMCQ.count > questionIndex   1 {
        questionIndex  = 1
    }
} label: {
    Text("Confirm Answer")
}

CodePudding user response:

You can use a @Statevar to remember the active index of your questions, and then just count up this index. By doing so there is no need for further views.

Usually you would count through the questions from a parent view and then have the child view display one single question (and answers).

struct Question: Identifiable {
    let id = UUID()
    var question: String
    var options: [String] =  ["One", "Two", "Three"]
}

struct ContentView: View {
    
    // dummy data
    let researchMCQ: [Question] = [
        Question(question: "First Question: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa qui"),
        Question(question: "Second Question: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa qui"),
        Question(question: "Third Question: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa qui"),
        Question(question: "Fourth Question: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa qui")
    ]
    
    // currently active question index
    @State private var activeQuestionIndex = 0
    
    //picked Option/Answer
    @State private var pickedOption = 0
    
    
    var body: some View {
        
        VStack(spacing: 1.0) {
            
            Group {
                Text(researchMCQ[activeQuestionIndex].question)
                    .padding(.bottom)
                
                Picker("Select Answer", selection: $pickedOption) {
                    Text(researchMCQ[activeQuestionIndex].options[0]).tag(0)
                    Text(researchMCQ[activeQuestionIndex].options[1]).tag(1)
                    Text(researchMCQ[activeQuestionIndex].options[2]).tag(2)
                }
                .pickerStyle(.segmented)
            }
            
            Spacer()
            
            Button(action: {
                if activeQuestionIndex < researchMCQ.count-1 {
                    self.activeQuestionIndex  = 1
                    self.pickedOption = 0
                }
            }) {
                Text("Confirm Answer")
            }
            .padding(.vertical, 12.5)
            .padding(.horizontal, 120)
            .foregroundColor(.white)
            .foregroundStyle(.background)
            .background(Color.primary)
            .clipShape(Capsule())
            
        }
        .padding()
    }
}
  • Related