Android material component: Filter and choice chips

Андрей Нетяга
6 min readJan 29, 2020

--

Chips is a material-component that has already become quite common and understandable to users. General approaches to working with it are well described on the official website of Material-components.

In this article, we will talk about two similar types of these components.

First type: there is a data set, and the user can select any number of items. This type of chips are called FilterChips.

Filter chips

This is look like the group of checkboxes, which of each works independently

Second type: there is a data set, and the user can select only one of items, or no one. This type of chips are called ChoiceChips.

Choice chips

This is look like the RadioButton group.

Let’s create simple project with those types of components, and find out some questions and difficulties. But primarily let’s make several preparations.

Project preparation

I hope most android developers use the Kotlin language, and no one will find it difficult to use examples on one.

So now we should make some actions in project. Firstly, to add last version of material-components library:

implementation 'com.google.android.material:material:1.2.0-alpha03'

At the time of writing this article the newest version is 1.2.0-alpha03, Currently, the current version can be found in maven-repository.

Secondly, the project theme should be made inheritable from`Theme.MaterialComponents. If you cannot change your theme to inherit from a Material Components theme, you can inherit from a Material Components Bridge theme. More about Bridge on material.io/Bridge_Themes. For example, if you have theme

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

you can change it to

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">

Let’s also add library core-ktx, that contains a lot of useful extensions for View and ViewGroup:

Android KTX is a set of Kotlin extensions that are included with Android Jetpack and other Android libraries.

Add it with gradle:

implementation 'androidx.core:core-ktx:1.1.0'

Group of elements with multiple choice

Let’s create a new project and make a layout with filter chips, where the user can select any number of elements. For that we should use special ViewGroup — ChipGroup:

A ChipGroup contains a set of Chips and manages their layout and multiple-exclusion scope.

This container has one important parameter that will be used later — singleSelection:

ChipGroup also supports a multiple-exclusion scope for a set of chips. When you set the app:singleSelectionattribute, checking one chip that belongs to a chip group unchecks any previously checked chip within the same group. The behavior mirrors that of RadioGroup.

Exactly this parameter determines behavior: single or multiple selection

Firstly let’s create layout for multiple selection. The parameter singleSelection must be false. it is worth noting that false is set by default, so you can not add it, but we will add it to this example for a clearer understanding. So, add four elements to the layout:

activity_main.xml

As we see for each chip is set the style Widget.MaterialComponents.Chip.Filter. Looking at the source you can see that this style has the following attributes:

filter_style.xml

These values mean that filter chips should not have the icon on the left, and the close button on the right. Of course you can override this style and specify new values, but it’s better to follow Google’s advice.

Also this style has checkedIcon, which is on the left in the checked state. By default, this is black icon, but you can choice different one by overriding this attribute:

Now launch the app with this layout and see the following result:

Listener for changing the filter

Now you need to register changes to filters. The container ChipGroup has a method setOnCheckedChangeListener, that takes the interface OnCheckedChangeListener as a parameter, and it seems that’s what we need. But actually it will not work in this case. It is invoked when parameter singleSelection is true, in other words when user can select one element only:

Register a callback to be invoked when the checked chip changes in this group. This callback is only invoked in single selection mode.

Ok, let’s find another solution.

Component Chip has method setOnCheckedChangeListener:

Register a callback to be invoked when the checked state of this button changes.

So let’s try to use it. Now we’ll go around all the elements of the container, find only Chip among them and set the state switching listeners on it, which will call the method that the filters have changed

chips_group.forEach { child ->
(child as? Chip)?.setOnCheckedChangeListener { _, _ ->
registerFilterChanged()
}
}

Our method registerFilterChanged() has no input parameters, that mean we can register changing of children states only. Now we need to create an app response to this change.

The registration of the filter changing

Now we should realize this method. After we received a notification that the set has changed, it is necessary to find out which elements are selected. We can use the method of container getCheckedChipIds():

Returns the identifiers of the selected Chips in this group. Upon empty selection, the returned value is an empty list.

val ids = chips_group.getCheckedChipIds()

After we have get the list of ids, we will find views on them and get the text from them:

val titles = mutableListOf<CharSequence>()

ids.forEach { id ->
titles.add(chips_group.findViewById<Chip>(id).text)
}

Now let’s show the result:

val text = if (titles.isNotEmpty()) {
titles.joinToString(", ")
} else {
"No Choice"
}

Toast.makeText(this, text, Toast.LENGTH_SHORT).show()

Full code:

And app result:

Group of elements with single choice

Now we will slightly modify our project so that the user can select only one element int the group. Let’s make a few changes in our project. First, let’s change the attribute singleSelection to true in the layout (We have described the purpose of this attribute above). Secondly, we should change the style of chips to Widget.MaterialComponents.Chip.Choice.

activity_main.xml

By default there are not many differences between Filter and Choice styles: firstly, single choice style hasn’t icon on checked state, and attribute is overridden:

<item name="checkedIconVisible">false</item>

Secondly, text and background colors are as selector with specific state:

<item name="android:textColor">@color/mtrl_choice_chip_text_color</item>

<item name="chipBackgroundColor">@color/mtrl_choice_chip_background_color</item>

It is worth noting that developers can customize the look of chips, and default style is Google recommendation only.

Launch the application and see how the components look and behave now:

The callback for selection

For single selection mode we can use the method of ChipGroup setOnCheckedChangeListener, because the singleSelection is now true. This method gets the interface ChipGroup.OnCheckedChangeListener as parameter. This interface has one method onCheckedChanged(CompoundButton buttonView, boolean isChecked)

Let’s try with method, find checked chip by id and show his title on Toast

chips_group.setOnCheckedChangeListener { chipGroup, checkedId ->
val
titleOrNull = chipGroup.findViewById<Chip>(checkedId)?.text
Toast.makeText(chipGroup.context, titleOrNull ?: "No Choice", Toast.LENGTH_LONG).show()
}

Now let’s launch app and check result:

Conclusion

I hope this article was useful! Give me feedback and write about better suggestions for using chips!

--

--