I am trying to do a survey app using Jetpack Compose and RadioButtons. I created a list with questions and answers
val surveyQuestions = listOf(
Question("question 1", listOf("answer 1", "answer 2")),
Question("question 2", listOf("answer 1", "answer 2", "answer 3")),
Question("question 3", listOf("answer 1", "answer 2"))
)
I created also a view (attachment).
How can I limit the number of answers to be selected to 1 per question?
How can I save the survey result in the form of listOf(question1 - answer2, question2 - answer)
, etc.?
CodePudding user response:
I would store such important info inside the viewmodel as a list like
var markedAnswers = mutableStateListOf<Int>()
Then add an update mechanism
fun onAnswerUpdate(index: Int, newAnswer: Int){
markedAnswer[index] = newAnswer
}
Now, just pass in this getter and setter to the Composables
MainActivity{
val viewModel by viewModels<...>(()
MyQuestionsComposable(
answers = viewModel.markedAnswers,
onAnswerUpdate = viewModel::onAnswerUpdate,
...
)
}
@Composable
fun MyQuestionsComposable (
questions: List<Question>, // I assume
answers: List,
onAnswerUpdate: (index, newAnswer) -> Unit
){
//I assume every question has three options for simplicity
/*and you must have access to the index of the question as it seems in the screenshot don't you?*/
//I'm using a loop for simplicity to gain the index, but you could do anything per your model
questions.forEachIndexed{ index, question ->
SurveyItem(
selectedAnswer = answers [index],
onAnswerUpdate = onAnswerUpdate,
options: List<...>
)
}
@Composable
fun SurveyItem(
selectedAnswer: Int,
options: List<...>,
onAnswerUpdate: (index, newAnswer) -> Unit
){
options.forEachIndexed{index, option ->
OptionComposable(
modifier = Modifier.clickable(onClick = onAnswerUpdate(index, option)),
selected = option == selectedAnswer
)
}
}
``
I'm storing selected answers as indices, and cross referencing them in the survey. Since it is mutable state, the selections will automatically update upon modification, and i have implemented this in a way that at a given time, only one answer can be selected.
I have followed Unidirectional Data Flow all over so it's best practiced. Don't worry about that.
Any doubts, just comment below.
CodePudding user response:
You need to store the selection as state. It depends on your data model, for example you can use mutableStateMapOf
:
val selectionStates = remember { mutableStateMapOf<Int, Int>()}
surveyQuestions.forEachIndexed { i, question ->
question.answers.forEachIndexed { j, answer ->
RadioButton(selected = selectionStates[i] == j, onClick = { selectionStates[i] = j })
}
}
If you are using the Lazy view, you can replace forEachIndexed
with itemsIndexed
.
You can also move selectionStates
from composable to view model to make sure it is not destroyed by rotation in case you support this.