Thursday, March 4, 2021

jetpack compose - Radio group example

Compose Radio Group
The RadioButton is a jetpack compose library widget. Android application developers use RadioButton to select an option from a list. This list of RadioButton widgets calls Radio Group. But there is no RadioGroup widget that exists in the jetpack compose library. So, how can android application developers display a Radio Group in the app user interface?

This android application development tutorial will guide us on how can we add a Radio Group to our jetpack compose application. The following code snippets add two Radio Groups inside a composable function and display the selected option from two groups.

To display a list of RadioButton, at first, we populate a list of items. Then we loop through the list items and render a RadioButton from each item inside a Column layout. As a result, we get a number of RadioButton widgets vertically positioned in a Column layout. Now we can call them all together a RadioGroup instance.

Now we have to implement our newly created RadioGroup proper behavior. RadioGroup acts as a group of RadioButtons where one RadioButton can be selected at once. Users can’t select multiple options at a time. And a RadioGroup should be preselected an item. So when we render a RadioGroup to the app user interface it should be preselected as a default item. Users can select a RadioButton by clicking itself. We also add accessibility here, that is users also can select an item from Radio Group by clicking the RadioButton label/text. To do that we build an annotated string with clickable text and show it on the RadioButton label.

We remember the user’s choice in a variable, so when users select an item from the RadioGroup we unselect all other items and only select the user-chosen item. We set a selected item from RadioGroup by clicking the RadioButton itself or the RadioButton label/text. Users can easily change their selection and also can change the preselected item but can’t deselect all items from a RadioGroup.

Copy the following code and paste it to your android studio jetpack compose application. Build the app and run the app in an emulator. So, you can easily understand how we make a Radio Group from a list of RadioButton objects. See the below screenshots, those also help you to understand the logic without running the emulator.
MainActivity.kt

package com.cfsuman.jetpackcompose

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            MainContent()
        }
    }


    @Composable
    fun MainContent(){
        val languageOptions: List<String> = listOf("Java", "Kotlin", "C#")
        val ideOptions: List<String> = listOf(
            "Android Studio", "Visual Studio", "IntelliJ Idea", "Eclipse"
        )

        Column{
            val selectedLanguage = radioGroup(
                radioOptions = languageOptions,
                title = "Which is your most favorite language?",
                cardBackgroundColor = Color(0xFFFFFAF0)
            )

            val selectedIDE = radioGroup(
                radioOptions = ideOptions,
                title = "Which is your most favorite IDE?",
                cardBackgroundColor = Color(0xFFF8F8FF)
            )

            Text(
                text = "Selected : $selectedLanguage & $selectedIDE",
                fontSize = 22.sp,
                fontStyle = FontStyle.Normal,
                fontWeight = FontWeight.Normal,
                fontFamily = FontFamily.SansSerif,
                modifier = Modifier
                    .padding(bottom = 15.dp)
                    .fillMaxWidth(),
                textAlign = TextAlign.Center,
                color = Color(0xFF665D1E)
            )
        }
    }



    @Composable
    fun radioGroup(
        radioOptions: List<String> = listOf(),
        title: String = "",
        cardBackgroundColor: Color = Color(0xFFFEFEFA)
    ):String{
        if (radioOptions.isNotEmpty()){
            val (selectedOption, onOptionSelected) = remember {
                mutableStateOf(radioOptions[0])
            }

            Card(
                backgroundColor = cardBackgroundColor,
                modifier = Modifier
                    .padding(10.dp)
                    .fillMaxWidth(),
                elevation = 8.dp,
                shape = RoundedCornerShape(8.dp),
            ) {
                Column(
                    Modifier.padding(10.dp)
                ) {
                    Text(
                        text = title,
                        fontStyle = FontStyle.Normal,
                        fontWeight = FontWeight.Bold,
                        modifier = Modifier.padding(5.dp),
                    )

                    radioOptions.forEach { item ->
                        Row(
                            Modifier.padding(5.dp),
                            verticalAlignment = Alignment.CenterVertically
                        ) {
                            RadioButton(
                                selected = (item == selectedOption),
                                onClick = { onOptionSelected(item) }
                            )

                            val annotatedString = buildAnnotatedString {
                                withStyle(
                                    style = SpanStyle(fontWeight = FontWeight.Bold)
                                ){ append("  $item  ") }
                            }

                            ClickableText(
                                text = annotatedString,
                                onClick = {
                                    onOptionSelected(item)
                                }
                            )
                        }
                    }
                }
            }
            return selectedOption
        }else{
            return ""
        }
    }


    @Preview
    @Composable
    fun ComposablePreview(){
        //MainContent()
    }
}