Categories UI & UX

Complete guide to master Material Design CheckBoxes for Android

22 Mar. 2019
0
0
12 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 CheckBoxes are part of these components. A Material DesignCheckBox represents a button with two states, either selected or unselected. Unlike radio buttons, if the state of a checkbox changes, it does not usually affect other checkboxes. A Material Design CheckBox is a rounded square button which contains a check to denote its current state.

Material Design CheckBoxes have various use cases. They can be used to allow the user to select one or more items from a set. For instance, CheckBoxes could be used to choose the ingredients that compose your meal. That is precisely what we are going to set up. We will create a simple screen that allows users to create their own burgers by choosing ingredients through checkboxes. Here is an overview of the project:

Material Design Checkboxes demo

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 MaterialCheckBox in your layout to create a Material Design CheckBox. A set of CheckBoxes allows the user to select multiple items. Therefore, each CheckBox is managed separately and you must register a click listener for each one.

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

Simple Checkbox

Showing a simple CheckBox would look like this:

<com.google.android.material.checkbox.MaterialCheckBox
        android:id="@+id/checkbox_bread"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/bread"
        android:checked="true"/>

As you can see, the state of the CheckBox can be configured in the layout using android:checked attribute. Similarly, a CheckBox can be enabled or disabled using android:enabled attribute. This last attribute is convenient if you want to create a conditional CheckBox, that is to say, a CheckBox whose activation state depends on another element. It could be another CheckBox that must be checked in order to enable the conditional CheckBox. We will study this behavior later in this post. The media below sums up the different states of the CheckBox.

CheckBox States

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

bread_checkbox.isChecked = false
bread_checkbox.isEnabled = false
MaterialCheckBox breadCheckbox = findViewById(R.id.checkbox_bread);

breadCheckbox.setChecked(false);
breadCheckbox.setEnabled(false);

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"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            tools:context=".MainActivity"
            android:padding="@dimen/medium_padding">

        <androidx.appcompat.widget.AppCompatTextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/build_your_own_burger"
                style="@style/TextAppearance.MaterialComponents.Headline6"
                android:layout_marginBottom="@dimen/medium_margin"/>

        <com.google.android.material.checkbox.MaterialCheckBox
                android:id="@+id/checkbox_bread"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/bread"
                android:checked="true"/>

        <com.google.android.material.checkbox.MaterialCheckBox
                android:id="@+id/checkbox_steak"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/steak"
                android:checked="true"/>

        <com.google.android.material.checkbox.MaterialCheckBox
                android:id="@+id/checkbox_double_steak"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/double_steak"
                android:checked="true"/>

        <com.google.android.material.checkbox.MaterialCheckBox
                android:id="@+id/checkbox_cheese"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/cheese"
                android:checked="true"/>

        <com.google.android.material.checkbox.MaterialCheckBox
                android:id="@+id/checkbox_tomato"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/tomato"
                android:checked="true"/>

        <com.google.android.material.checkbox.MaterialCheckBox
                android:id="@+id/checkbox_lettuce"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/lettuce"
                android:checked="true"/>

        <com.google.android.material.button.MaterialButton
                android:id="@+id/reset_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/reset"/>

        <androidx.appcompat.widget.AppCompatTextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/overview"
                style="@style/TextAppearance.MaterialComponents.Headline6"
                android:layout_marginTop="@dimen/medium_margin"/>

        <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/top_bread"
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:src="@drawable/top_bread"
                android:adjustViewBounds="true"
                android:layout_gravity="center_horizontal"
                android:layout_marginTop="@dimen/large_margin"/>

        <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/tomato"
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:src="@drawable/tomato"
                android:adjustViewBounds="true"
                android:layout_gravity="center_horizontal"/>

        <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/cheese"
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:src="@drawable/cheese"
                android:adjustViewBounds="true"
                android:layout_gravity="center_horizontal"/>

        <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/steak"
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:src="@drawable/steak"
                android:adjustViewBounds="true"
                android:layout_gravity="center_horizontal"/>

        <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/lettuce"
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:src="@drawable/lettuce"
                android:adjustViewBounds="true"
                android:layout_gravity="center_horizontal"/>

        <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/double_steak"
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:src="@drawable/steak"
                android:adjustViewBounds="true"
                android:layout_gravity="center_horizontal"/>

        <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/bottom_bread"
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:src="@drawable/bottom_bread"
                android:adjustViewBounds="true"
                android:layout_gravity="center_horizontal"/>

        <com.google.android.material.button.MaterialButton
                android:id="@+id/order_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/order"
                android:layout_gravity="center_horizontal"
                android:layout_marginTop="@dimen/medium_margin"
                android:layout_marginBottom="@dimen/medium_margin"/>

        <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/order_confirmation"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
    </LinearLayout>
</ScrollView>

To clarify, each burger part has an image. All the parts of the burger are placed in a LinearLayout in order to gather them automatically when a part is removed or added.

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

bread_checkbox.setOnCheckedChangeListener { buttonView, isChecked ->
    // Action
}
MaterialCheckBox breadCheckbox = findViewById(R.id.checkbox_bread);

breadCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        // Action
    }
});

In our project, the action consists in changing the visibility of the related part of the burger. That is to say that when a CheckBox, for instance, the tomato CheckBox, is checked, the image containing the tomato should be visible. Otherwise, it should be gone.

Conditional CheckBox

A conditional CheckBox is a CheckBox whose activation state depends on the check state of another CheckBox. In our case, the double steak CheckBox can only be checked if the simple steak CheckBox is checked. Conditional CheckBoxes are really easy to implement.

Conditional CheckBox
steak_checkbox.setOnCheckedChangeListener { buttonView, isChecked ->
        steak.setVisibility(isChecked)
    double_steak_checkbox.isEnabled = isChecked

    if (!isChecked) {
        double_steak_checkbox.isChecked = false
    }
}
steakCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        setVisibility(steak, isChecked);
        doubleSteakCheckbox.setEnabled(isChecked);

        if(!isChecked) {
            doubleSteakCheckbox.setChecked(false);
        }
    }
});

Custom Checkbox

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

<com.google.android.material.checkbox.MaterialCheckBox
        android:id="@+id/custom_checkbox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Custom checkbox"
        android:button="@drawable/custom_checkbox"
        android:checked="true"/>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:drawable="@drawable/unchecked_checkbox"
          android:state_checked="false"/>
    <item android:drawable="@drawable/selected_checkbox"
          android:state_checked="true"/>
    <item android:drawable="@drawable/unchecked_checkbox"/>
</selector>
Note that the drawable of the CheckBox can also be changed programmatically using the setButtonDrawable(drawable) method.

Dynamic CheckBox

Sometimes you may fetch options from a remote database and need to create Checkboxes dynamically. A CheckBox can be added programmatically as follows:

val checkBox = MaterialCheckBox(this)
checkBox.text = "Onions"
checkBox.setOnCheckedChangeListener {
        // Action
}

linear_layout.addView(checkBox);
LinearLayout linearLayout = findViewById(R.id.rootContainer);

MaterialCheckBox checkBox = new MaterialCheckBox(this);
checkBox.setText("Onions");
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        // Action
    }
});

linearLayout.addView(checkBox);

Download

  • Kotlin
  • Java

Conclusion

In conclusion, Material Design CheckBoxes are useful selection controls that allow users to complete tasks that involve making choices. CheckBoxes should be used to select one or multiple items from a list. These components have the advantage to inherit from CompoundButton, ButtonTextView, View so it has all their properties. Therefore, they are fully customizable.

Leave a Reply

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