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:
- 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]
- Have another variable to hold the current question.
@State private var questionIndex = 0
- Also
buttonConfirm
should be an array in this case.
@State public var buttonConfirm = [Int?]()
- Show the current question (see how the variable
researchMCQ
is used here).
Group {
Text(researchMCQ[questionIndex].question)
.padding(.trailing, 5)
- 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 @State
var 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()
}
}