0

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])

}

}

2 Answers 2

2

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.append(button)
    // or this, if you initialize the var with the whole array:
    // 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")
}
Sign up to request clarification or add additional context in comments.

6 Comments

So I have followed your steps and have one question, now I have made all the changes the toggles in the vstack (specifically the research methods.options[] part) all have errors stating 'Value of type '[Question]' has no member 'options''. Is there any way I can get around this? Thankyou for your help :)
@User8149: this should be an issue with the toggles. Replace ResearchMCQ.options[0] with researchMCQ[questionIndex].options[0]. Basically, almost everywhere ResearchMCQ (which before was only a single question) needs to be changed to researchMCQ[questionIndex] (which is now how you refer to the single question in the array) - do that in case you get more of these messages.
That's great thank you. Unfortunately, the error - Thread 1: Fatal error: Index out of range, now appears when I try not run the code on the simulator. This happens where I have coded the group section
@User8149: does it happen when you reach the final question? You need to check for out-of-bounds errors. I have edited the answer to include one check, see line if researchMCQ.count > questionIndex + 1. There could be the need to check for other issues, like an empty array of questions, but we're starting to drift away from the scope of this question.
No, as soon as I click continue on the home page to have the questions appear the simulator closes and the error appears. But no worries, thank you for your help with the above code :)
|
1

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()
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.