Categories UI & UX

Complete guide to master Material Design Radio Buttons for Android

1 Apr. 2019
0
0
11 minutes

Material Design is a set of guides for visual, interaction and motion design that enhance your engineering workflow. Google provides developers with many Material Design Components to build intuitive and beautiful applications. Material Design Radio Buttons are part of these components. A Material Design Radio Button represents a button with two states, either selected or unselected. Unlike CheckBoxes, if the state of a Radio Button changes, it usually affects other Radio Buttons. Indeed, selecting RadioButton inRadioGroup will de-select all other radio buttons in that group. A Material Design Radio Button is a circle which fills in with an inset when it is selected. Note that unlike Checkboxes, a radio button cannot be unchecked by the user once checked. However the user can choose another option.

Material Design Radio Buttons should be used to help the user to select a single option from a list where options are mutually exclusive. Naturally, it should expose all available options. For instance, Material Design Radio Buttons could be used to choose a meal size, a gender, or to grade a service. We will create a simple screen that allows users to order coffee by choosing its size through Radio Buttons. Here is an overview of the project:

Material Design Radio Buttons

Video

Setup

First and foremost, you need to add Material Components library to the dependencies section in your gradle file:

dependencies {
    // ...
    implementation 'com.google.android.material:material:1.1.0-alpha04'
    // ...
  }

This library comes along the newly package Androidx. Therefore, if your app relies on the original Design Support library, you can migrate your project to Androidx using the option provided by Android Studio.

If you want to keep the original Design Support library, you can also use Material Components through this library :

dependencies {
    // ...
    implementation 'com.android.support:design:28.0.0'
    // ...
  }
You should not use the com.android.support and com.google.android.material dependencies in your app at the same time.

Check you are using AppCompatActivity to ensure that all the Material Components work correctly.

Finally, change your app theme to inherit from a Material Components Theme among the following list :

  • Theme.MaterialComponent
  • Theme.MaterialComponents.NoActionBar
  • Theme.MaterialComponents.Light
  • Theme.MaterialComponents.Light.NoActionBar
  • Theme.MaterialComponents.Light.DarkActionBar

The Theme.MaterialComponents.Light is the theme used in the project.

<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

Implementation

Material Design CheckBoxes are very simple to implement.
You need to use MaterialRadioButton in your layout to create a Material Design Radio Button.

The Radio Button inherits from CompoundButton, Button, TextView, View so it has all their properties.

Simple Radio Button

Showing a simple Radio Button would look like this:

<com.google.android.material.radiobutton.MaterialRadioButton
        android:id="@+id/radio_small"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/small"
        android:checked="true"/>

As you can see, the state of the Radio Button can be configured in the layout using android:checked attribute. Similarly, a Radio Button can be enabled or disabled using android:enabled attribute. This last attribute is convenient if you want to create a conditional Radio Button, that is to say, a Radio Button whose activation state depends on another element. The media below sums up the different states of the Radio Button.

Radio Button states

The activation state and the check states can also be edited programmatically as follows:

medium_radio_button.isChecked = false
medium_radio_button.isEnabled = false
MaterialRadioButton mediumRadioButton = findViewById(R.id.radio_medium);

mediumRadioButton.setChecked(false);
mediumRadioButton.setEnabled(false);

Radio Buttons are usually used together in RadioGroup. This class is used to create a multiple-exclusion scope for a list of Radio Buttons. It means that checking a single Radio Button that belongs to a Radio Group unchecks any previously Radio Button that has been checked within the same group. Note that the Radio Group inherits from LinearLayout so you can set its orientation as vertical or horizontal. A Radio Button within a Radio Group can be checked by default using android:checkedButton attribute. Note that an item can also be checked programmatically thanks to check(int id) method. By contrast, the selection can be cleared using clearCheck() method on the instance of the Radio Group.

Here is the layout file of our burger project:

<ScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            tools:context=".MainActivity"
            android:padding="@dimen/medium_padding">

        <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/coffee_size_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/coffee_size"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                style="@style/TextAppearance.MaterialComponents.Headline6"/>

        <RadioGroup
                android:id="@+id/coffee_size_radio_group"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toBottomOf="@id/coffee_size_label"
                android:layout_marginTop="@dimen/medium_margin">

            <com.google.android.material.radiobutton.MaterialRadioButton
                    android:id="@+id/radio_small"
                    android:text="@string/small"
                    android:checked="true"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"/>

            <com.google.android.material.radiobutton.MaterialRadioButton
                    android:id="@+id/radio_medium"
                    android:text="@string/medium"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"/>

            <com.google.android.material.radiobutton.MaterialRadioButton
                    android:id="@+id/radio_large"
                    android:text="@string/large"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"/>
        </RadioGroup>

        <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/coffee_size_preview"
                android:layout_width="wrap_content"
                android:layout_height="300dp"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toBottomOf="@id/coffee_size_radio_group"
                android:src="@drawable/small_coffee"
                android:layout_marginTop="@dimen/medium_margin"/>

        <com.google.android.material.button.MaterialButton
                android:id="@+id/order_button"
                android:text="@string/order"
                app:layout_constraintTop_toBottomOf="@id/coffee_size_preview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"/>

        <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/order_confirmation"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/medium_margin"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toBottomOf="@id/order_button"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

An action can be performed when the state of a RadioButton changes. You need to register a callback to be invoked when the checked state of the Radio Button in a Radio Group changes. The sample below shows how to register such a callback.

coffee_size_radio_group.setOnCheckedChangeListener { group, checkedId ->
    when(checkedId) {
        R.id.radio_small -> coffee_size_preview.setImageResource(R.drawable.small_coffee)
        R.id.radio_medium -> coffee_size_preview.setImageResource(R.drawable.medium_coffee)
        R.id.radio_large -> coffee_size_preview.setImageResource(R.drawable.large_coffee)
    }
}
final RadioGroup coffeeSizeRadioGroup = findViewById(R.id.coffee_size_radio_group);

coffeeSizeRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        switch (checkedId) {
            case R.id.radio_small:
                coffeePreview.setImageResource(R.drawable.small_coffee);
                break;
            case R.id.radio_medium:
                coffeePreview.setImageResource(R.drawable.medium_coffee);
                break;
            case R.id.radio_large:
                coffeePreview.setImageResource(R.drawable.large_coffee);
                break;
        }
    }
});

In our project, the action consists in changing the resource of the image view.

Note that you can get the identifier of the selected radio button in a Radio Group by calling getCheckedRadioButtonId() method on the RadioGroup’s instance.

Custom Radio Button

Material Design Radio Buttons can be easily customized. By default, the color of a checked Radio Button is the accent color defined in your project. It can be changed using android:buttonTint attribute. As a Radio Button inherits from the Button, you can just change its style using the android:button attribute as follows.

<com.google.android.material.checkbox.MaterialRadioButton
        android:id="@+id/custom_radio_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Custom radio button"
        android:button="@drawable/custom_radio_button"
        android:checked="true"/>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_checked="false" android:drawable="@drawable/checkbox_not_checked" />
     <item android:state_checked="true" android:drawable="@drawable/checked_radio_button" />
     <item android:drawable="@drawable/unchecked_radio_button" /> 
</selector>
Note that the drawable of the Radio Button can also be changed programmatically using the setButtonDrawable(drawable) method.

Dynamic Radio Button

Sometimes you may fetch options from a remote database and need to create Radio Buttons dynamically. A Radio Button can be added programmatically in a Radio Group as follows:

val materialRadioButton = MaterialRadioButton(this)
materialRadioButton.text = "Dynamic radio button"
coffeeSizeRadioGroup.addView(materialRadioButton)
MaterialRadioButton materialRadioButton = new MaterialRadioButton(this);
materialRadioButton.setText("Dynamic radio button");
coffeeSizeRadioGroup.addView(materialRadioButton);

Download

  • Kotlin
  • Java

Conclusion

In conclusion, Material Design Radio Buttons are useful selection controls that allow users to complete tasks that involve making choices. CheckBoxes should be used to select a single option from a set of mutually-exclusive options. These components have the advantage to inherit from CompoundButton, Button, TextView, Viewso it has all their properties. Therefore, they are fully customizable.

Leave a Reply

Your email address will not be published. Required fields are marked *