Categories UI & UX

How to easily implement Material Design Chips for Android

11 Mar. 2019
5
0
12 minutes
Material Design Chips

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 Chips are part of these components. These components are compact elements that represent an action, attribute, or input. Material Design Chips should represent discrete information with a clear relationship with the context. These components should make tasks easier to complete and enhance the User Experience.

In concrete terms, Chips are small blocks that represent a complex entity. It is a rounded component that consists of a label, an optional chip icon, and an optional close icon. Chips can be toggled or clicked according to their type.

Demonstration

This post focuses on the implementation of :

  • Action Chips
  • Entry Chips
  • Filter Chips
  • Choice Chips
  • Custom Chips
  • Dynamically added Chips
Material Design Chips Demonstration

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

There are four types of chips :

  • Action Chips (default)
  • Entry Chips
  • Filter Chips
  • Choice Chips

Chips are contained in a ChipGroup which is a flow layout that is able to manage multiple-exclusion scope.

ChipGroup

A ChipGroup adjusts its size across multiple lines according to the chips it contains. It can hold both declared chips, or chips added dynamically.

<com.google.android.material.chip.ChipGroup
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

  <!-- Chips -->

</com.google.android.material.chip.ChipGroup>

ChipGroup can also constrain its children to a single horizontal line using the app:singleLineattribute.

Action Chips

Action Chips are used to trigger an action related to primary content. These components contain an optional icon and are never checkabke.

Action Chips
<com.google.android.material.chip.ChipGroup
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.google.android.material.chip.Chip
        android:id="@+id/turn_on_light_chip"
        style="@style/Widget.MaterialComponents.Chip.Action"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/turn_on_lights"
        app:chipIcon="@drawable/ic_lightbulb_outline_black_24dp"
        app:chipIconTint="@color/chip_icon_tint"/>

</com.google.android.material.chip.ChipGroup>

In order to trigger an action, you need to define it programmatically through a click listener and then, bind it to the chip.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val lightChip: Chip = findViewById(R.id.turn_on_light_chip)

    showSnackbarOnClick(lightChip, getString(R.string.lights_on))
}

private fun showSnackbarOnClick(view: View, message: String) {
    view.setOnClickListener { Snackbar.make(view, message, Snackbar.LENGTH_SHORT).show() }
}
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Chip lightChip = findViewById(R.id.turn_on_lights_chip);

    showSnackbarOnClick(lightChip, getString(R.string.lights_on));
}

private void showSnackbarOnClick(final View view, final String message) {
    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Snackbar.make(view, message, Snackbar.LENGTH_SHORT).show();
        }
    });
}

Entry Chips

An Entry Chip represents a complex piece of information used in input fields. It contains an optional chip icon, an optional close icon, and is optionally checkable.

Entry Chips
<com.google.android.material.chip.ChipGroup
    android:id="@+id/entry_chip_group"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.google.android.material.chip.Chip
        style="@style/Widget.MaterialComponents.Chip.Entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/montreal"
        app:chipIcon="@drawable/ic_location_on_black_24dp"
        app:chipIconTint="@color/chip_icon_tint"/>

    <com.google.android.material.chip.Chip
        style="@style/Widget.MaterialComponents.Chip.Entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/mountains"
        app:chipIcon="@drawable/ic_terrain_black_24dp"
        app:chipIconTint="@color/chip_icon_tint"/>

    <com.google.android.material.chip.Chip
        style="@style/Widget.MaterialComponents.Chip.Entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/biking"
        app:chipIcon="@drawable/ic_directions_bike_black_24dp"
        app:chipIconTint="@color/chip_icon_tint"/>

</com.google.android.material.chip.ChipGroup>

You can define an action that is triggered when the user clicks on the close icon of a chip. A common action consists in removing the Chip from its ChipGroup.

val entryChipGroup: ChipGroup = findViewById(R.id.entry_chip_group)

for(i in 0 until entryChipGroup.childCount) {
    val entryChip: Chip = entryChipGroup.getChildAt(i) as Chip
    entryChip.setOnCloseIconClickListener { view -> entryChipGroup.removeView(view)}
}
final ChipGroup entryChipGroup = findViewById(R.id.entry_chip_group);

for(int i = 0; i < entryChipGroup.getChildCount(); i++) {
    final Chip entryChip = (Chip) entryChipGroup.getChildAt(i);

    entryChip.setOnCloseIconClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            entryChipGroup.removeView(view);
        }
    });
}


Filter Chips

Filter Chips are used to filter collections. Consequently, it should include descriptive words or tags. These Chips are always checkable and contain an optional chip icon as well as an optional close icon.

For instance, a movie list could be filtered according to Filter Chips representing genres.

Filter Chips
<com.google.android.material.chip.ChipGroup
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.google.android.material.chip.Chip
        style="@style/Widget.MaterialComponents.Chip.Filter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/genre_action"/>

    <com.google.android.material.chip.Chip
        style="@style/Widget.MaterialComponents.Chip.Filter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/genre_comedy"/>

    <com.google.android.material.chip.Chip
        style="@style/Widget.MaterialComponents.Chip.Filter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/genre_horror"/>

</com.google.android.material.chip.ChipGroup>

An action can be triggered when a chip is toggled using OnCheckedChangeListener.

Choice Chips

Another kind of Chip is the Choice Chip. It helps users to make a single selection from a finite set of options. It is always checkable and it has an optional chip icon.

For example, a food ordering app could use Choice Chips to help users choose a drink size.

Choice Chips
<com.google.android.material.chip.ChipGroup
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:singleSelection="true">

    <com.google.android.material.chip.Chip
        style="@style/Widget.MaterialComponents.Chip.Choice"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/size_small"/>

    <com.google.android.material.chip.Chip
        style="@style/Widget.MaterialComponents.Chip.Choice"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/size_medium"/>

    <com.google.android.material.chip.Chip
        style="@style/Widget.MaterialComponents.Chip.Choice"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/size_large"/>

</com.google.android.material.chip.ChipGroup>

Notice the presence of app:singleSelection attribute. It ensures that a single chip to be checked at a time.

Custom Chips

Material Design Chips comprise a wide range of attributes. As a result, these components are fully customizable.

Custom Chip

Here is the related code :

<com.google.android.material.chip.Chip
    style="@style/Widget.MaterialComponents.Chip.Action"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:chipStrokeWidth="1dp"
    app:chipStrokeColor="@color/chip_stroke_color"
    app:chipBackgroundColor="@color/white"
    app:chipIconTint="@color/chip_icon_tint"
    app:chipIcon="@drawable/ic_account_circle_black_24dp"
    android:text="@string/custom_chip"/>

Here is a non-exhaustive list of Chip’s attributes:

  • android:text
  • android:textAppearance
  • app:chipCornerRadius
  • app:chipMinHeight
  • app:chipBackgroundColor 
  • app:chipStrokeColor
  • app:chipStrokeWidth
  • app:rippleColor 
  • app:chipIconVisible
  • app:chipIcon
  • app:chipIconTint
  • app:chipIconSize 
  • app:closeIconVisible
  • app:closeIcon
  • app:closeIconSize
  • app:closeIconTint 
  • android:checkable
  • app:checkedIconVisible
  • app:checkedIcon 
  • app:showMotionSpec
  • app:hideMotionSpec
  •  app:chipStartPadding
  • app:iconStartPadding
  • app:iconEndPadding
  • app:textStartPadding
  • app:textEndPadding
  • app:closeIconStartPadding
  • app:closeIconEndPadding
  • app:chipEndPadding
  • app:chipMinTouchTargetSize

Chips added programmatically

Chips can be added programmatically to match your needs.

Dynamic Chip

The code below shows a chip created dynamically with custom attributes. It is added to an exisiting ChipGroup afterward.

val dynamicChip = Chip(this)

dynamicChip.text = getString(R.string.dynamic_chip)
dynamicChip.chipIcon = ContextCompat.getDrawable(this, R.drawable.ic_account_circle_black_24dp)
dynamicChip.isCloseIconVisible = true
dynamicChip.isCheckable = true

val dynamicChipGroup: ChipGroup = findViewById(R.id.dynamic_chip_group)
dynamicChipGroup.addView(dynamicChip)
Chip dynamicChip = new Chip(this);

dynamicChip.setText(getString(R.string.dynamic_chip));
dynamicChip.setChipIcon(ContextCompat.getDrawable(this,
        R.drawable.ic_account_circle_black_24dp));
dynamicChip.setCloseIconVisible(true);
dynamicChip.setCheckable(true);

ChipGroup dynamicChipGroup = findViewById(R.id.dynamic_chip_group);
dynamicChipGroup.addView(dynamicChip);

ChipDrawable

In contexts that require a Drawable, you can use a standalone ChipDrawable instead of a Chip. For instance, an AppCompatAutoCompleteTextView can replace snippets of text with ChipDrawable element using a span to represent it as a semantic entity.

All the attributes on Chip can be applied to a ChipDrawable component.

Download

  • Kotlin
  • Java

Conclusion

To sum up, Material Design Chips allow users to trigger actions, enter information, make choice and filter content. These components have a nice and intuitive appearance. Therefore, they enhance User Experience.

Leave a Reply

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