'How to add chips from Material Components library to input field in android?
I've seen that in android-P google add new material components library which contains material chips:
Material components for android
So I decided to add material input chips to my project, but unfortunately didn't find any tutorial how to make that. I want to create something like Gmail chips but without image on the start.
Because I'm using appcompat library I tried to use material chips by android.support.design.chip.Chip and android.support.design.chip.ChipGroup.
But result was just chips without any input field. Also I tried to create a Standalone ChipDrawable and then add it to EditText using
Editable text = editText.getText();
text.setSpan(span, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
But I got empty EditText without any chips. So how can I create chips input like in Gmail using this material components library? Maybe someone has expreience or knows any tutorials where I could see how to create this?
Thanks in advance!
Solution 1:[1]
All of the previous solutions didn't work for me if you want to achieve a gmail like behaviour with chips on multiple lines. In order to do that I had to avoid using the ChipGroup and instead using a FlexboxLayout.
your_recipient_layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/recipient_label_TV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_gravity="center_vertical" />
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/recipient_group_FL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_gravity="center_vertical"
app:flexWrap="wrap"
app:alignItems="stretch"
app:alignContent="space_around"
app:showDivider="beginning|middle|end"
app:dividerDrawable="@drawable/divider">
<EditText
android:id="@+id/recipient_input_ET"
android:layout_width="wrap_content"
android:layout_height="32dp"
app:layout_flexGrow="1"
android:background="@android:color/transparent"
android:imeOptions="actionDone"
android:inputType="text"/>
</com.google.android.flexbox.FlexboxLayout>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recipients_list_RV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
The trick now is adding a new chip to the group but as second last position. Something like this:
private fun addNewChip(person: String, chipGroup: FlexboxLayout) {
val chip = Chip(context)
chip.text = person
chip.chipIcon = ContextCompat.getDrawable(requireContext(), R.mipmap.ic_launcher_round)
chip.isCloseIconEnabled = true
chip.isClickable = true
chip.isCheckable = false
chipGroup.addView(chip as View, chipGroup.childCount - 1)
chip.setOnCloseIconClickListener { chipGroup.removeView(chip as View) }
}
Solution 2:[2]
We can do this by using material chips design itself without adding any extra styles.
Add it on app gradle For AndroidX
implementation 'com.google.android.material:material:1.0.0-beta01'
For earlier than AndroidX use this
implementation 'com.android.support:design:28.0.0'
Fragment
class EntryChipDemoFragment : Fragment() {
private lateinit var mView: View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
mView = inflater.inflate(R.layout.fragment_entry_chip_demo, container, false)
mView.etValue.setOnEditorActionListener(TextView.OnEditorActionListener { v, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
val txtVal = v.text
if(!txtVal.isNullOrEmpty()) {
addChipToGroup(txtVal.toString(), mView.chipGroup2)
mView.etValue.setText("")
}
return@OnEditorActionListener true
}
false
})
return mView
}
private fun addChipToGroup(txt: String, chipGroup: ChipGroup) {
val chip = Chip(context)
chip.text = txt
// chip.chipIcon = ContextCompat.getDrawable(requireContext(), baseline_person_black_18)
chip.isCloseIconEnabled = true
chip.setChipIconTintResource(R.color.chipIconTint)
// necessary to get single selection working
chip.isClickable = false
chip.isCheckable = false
chipGroup.addView(chip as View)
chip.setOnCloseIconClickListener { chipGroup.removeView(chip as View) }
printChipsValue(chipGroup)
}
private fun printChipsValue(chipGroup: ChipGroup) {
for (i in 0 until chipGroup.childCount) {
val chipObj = chipGroup.getChildAt(i) as Chip
Log.d("Chips text :: " , chipObj.text.toString())
}
}
companion object {
@JvmStatic
fun newInstance() = EntryChipDemoFragment()
}
}
XML File:
<HorizontalScrollView
android:id="@+id/chipGroup2HorizontalView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:scrollbars="none"
app:layout_constraintVertical_bias="0.62">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Skills: " />
<com.google.android.material.chip.ChipGroup
android:id="@+id/chipGroup2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:duplicateParentState="false">
</com.google.android.material.chip.ChipGroup>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout"
android:layout_width="wrap_content"
android:layout_height="43dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="5dp"
android:minWidth="32dp"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/chipGroup2HorizontalView"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_min="32dp">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/etValue"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:imeOptions="actionDone"
android:maxLines="1"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</HorizontalScrollView>
For more reference Click Here
Solution 3:[3]
You can use material chip "com.google.android.material.chip.Chip" and "implementation 'com.google.android.material:material:1.0.0' " add in build.gradle
Filter style="@style/Widget.MaterialComponents.Chip.Filter"
Choice Chips style="@style/Widget.MaterialComponents.Chip.Choice"
Entry input: style="@style/Widget.MaterialComponents.Chip.Entry"
Solution 4:[4]
Using TextInputLayout
chip_item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.chip.Chip xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.Chip.Action"
app:closeIconEnabled="true"
android:layout_width="wrap_content" />
tags_input_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/i_input_v"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:hint="Tags">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:gravity="bottom"
android:paddingBottom="22dp"
android:layout_height="match_parent" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.chip.ChipGroup
android:id="@+id/i_flex_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:alignContent="space_around"
app:alignItems="stretch"
app:flexWrap="wrap"
android:layout_marginTop="12dp"
android:layout_marginBottom="50dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:showDivider="beginning|middle|end">
</com.google.android.material.chip.ChipGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
TagInputView.kt
class TagInputView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : ConstraintLayout(context, attrs) {
val chipGroup: ChipGroup
init {
LayoutInflater.from(context).inflate(R.layout.tags_input_layout, this, true)
val inputLayout = findViewById<TextInputLayout>(R.id.i_input_v)
val editText = inputLayout.editText!!
chipGroup = findViewById(R.id.i_flex_box)
editText.onFocusChangeListener = OnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
if (editText.text.toString() == " "){
editText.text.clear()
}
} else {
if (editText.text.isNullOrEmpty() && chipGroup.childCount > 0) {
editText.setText(" ")
}
}
}
editText.setOnKeyListener { _, _, event ->
if (event.action == KeyEvent.ACTION_DOWN) {
// onBackspacePressed, also edittext is empty
if (chipGroup.childCount <= 0) return@setOnKeyListener false
val lastChip = chipGroup.getChildAt(chipGroup.childCount - 1) as Chip
editText.append(lastChip.text)
chipGroup.removeView(lastChip)
}
false
}
editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun afterTextChanged(editable: Editable) {
val text = editable.toString()
if (text.isNotEmpty() && text.endsWith(",")) {
addNewChip(text.removeSuffix(","))
editable.clear()
}
}
})
}
private fun addNewChip(text: String) {
val newChip =
LayoutInflater.from(context).inflate(R.layout.chip_item, chipGroup, false) as Chip
newChip.id = ViewCompat.generateViewId()
newChip.text = text
newChip.setOnCloseIconClickListener {
chipGroup.removeView(newChip)
}
chipGroup.addView(newChip)
}
}
Usage
activity_main.xml
...
<com.shubhamgupta16.yourappid.utils.TagInputView
android:id="@+id/tagInputView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
...
You can also access all Chip inside ChipGroup by using tagInputView.chipGroup property.
Output
Solution 5:[5]
Not the ideal solution, but definitely easy
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.chip.Chip
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chipMinTouchTargetSize="0dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="10">
<EditText
android:id="@+id/add_frag_label_et_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="8dp"
android:layout_weight="9"
android:background="@null"
android:hint="Enter Label"
android:inputType="text"
android:paddingStart="8dp"
android:paddingEnd="0dp"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="@color/black"
android:textSize="14sp" />
<ImageView
android:id="@+id/add_frag_label_iv_add"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
app:tint="#6b6a6c"
android:layout_weight="1"
android:contentDescription="Add Label to note."
android:src="@mipmap/ic_plus_foreground" />
</LinearLayout>
</FrameLayout>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | br00 |
| Solution 2 | Naveen Kumar M |
| Solution 3 | Arul Pandian |
| Solution 4 | Shubham Gupta |
| Solution 5 | shekhar g h |



