Home > Software engineering >  Detect what answer is selected in RadioButton using Jetpack compose
Detect what answer is selected in RadioButton using Jetpack compose

Time:09-17

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

enter image description here

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.

  • Related