Few popular questions & solutions
1] Roman Nurik : https://plus.google.com/113735310430199015092/posts/WUd7GrfZfiZ
2] Android EditText Gmail like Field : http://stackoverflow.com/questions/13747809/android-edittext-gmail-like-to-field
3] Android Labels or Bubbles in Edit Text : http://stackoverflow.com/questions/8090711/android-labels-or-bubbles-in-edittext/8128848#8128848
4] Contact Bubble Edit Text : http://stackoverflow.com/questions/10812316/contact-bubble-edittext
While I was reading above post, I thought that, I should develop Chips Edit Text control, which should be easy to understand and integrated in project. Here, My control is named as "Chips Edit Text". Before going to technical details, I would like to show few screenshots.


Step 1: Prerequisite
Android provides bunch of Span classes, Span classes are used to format text. I suggest to read following articles for helpful detail and in-depth understanding.
1] Introduction to Span
http://blog.stylingandroid.com/archives/177
2] Easy Method for Formatting Android
http://www.androidengineer.com/2010/08/easy-method-for-formatting-android.html
3] API Classes : Spannable, SpannableString, SpannableStringBuilder, ImageSpan ,ClickableSpan
Step 2 : Logic
Our goal is to display background (border & fill with color) and image at right side of every chip. Android spannable classes allow us to set background color only. It does not support any drawable at background. Another problem is right side image. Android has ImageSpan class, we can display image at right side with ImageSpan but problem is that ImageSpan will consider as separate entity and it will display outside of background.
I have implemented following logic to overcome above two problems
1. Extends MultiAutoCompleteTextView to create chips edit text.
2. Generate TextView dynamically in code and set style & drawable at right side.
3. Capture image/bitmap of newly generated TextView.
4. Set ImageSpan instead-of country name.
Step 3 : Create Android Project
Create Android project named "Chips Edit Text"
Step 4 : Create class named "ChipsMultiAutoCompleteTextview.java"
package com.kpbird.chipsedittext;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextWatcher;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.MultiAutoCompleteTextView;
import android.widget.TextView;
public class ChipsMultiAutoCompleteTextview extends MultiAutoCompleteTextView implements OnItemClickListener {
private final String TAG = "ChipsMultiAutoCompleteTextview";
// Constructor
public ChipsMultiAutoCompleteTextview(Context context) {
super(context);
init(context);
}
// Constructor
public ChipsMultiAutoCompleteTextview(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
// Constructor
public ChipsMultiAutoCompleteTextview(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init(context);
}
// set listeners for item click and text change
public void init(Context context){
setOnItemClickListener(this);
addTextChangedListener(textWather);
}
// TextWatcher, If user type any country name and press comma then following code will regenerate chips
private TextWatcher textWather = new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(count >=1){
if(s.charAt(start) == ',')
setChips(); // generate chips
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,int after) {}
@Override
public void afterTextChanged(Editable s) {}
};
//This function has whole logic for chips generate
public void setChips(){
if(getText().toString().contains(",")) // check comman in string
{
SpannableStringBuilder ssb = new SpannableStringBuilder(getText());
// split string wich comma
String chips[] = getText().toString().trim().split(",");
int x =0;
// loop will generate ImageSpan for every country name separated by comma
for(String c : chips){
// inflate chips_edittext layout
LayoutInflater lf = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
TextView textView = (TextView) lf.inflate(R.layout.chips_edittext, null);
textView.setText(c); // set text
setFlags(textView, c); // set flag image
// capture bitmapt of genreated textview
int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
textView.measure(spec, spec);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
Bitmap b = Bitmap.createBitmap(textView.getWidth(), textView.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(b);
canvas.translate(-textView.getScrollX(), -textView.getScrollY());
textView.draw(canvas);
textView.setDrawingCacheEnabled(true);
Bitmap cacheBmp = textView.getDrawingCache();
Bitmap viewBmp = cacheBmp.copy(Bitmap.Config.ARGB_8888, true);
textView.destroyDrawingCache(); // destory drawable
// create bitmap drawable for imagespan
BitmapDrawable bmpDrawable = new BitmapDrawable(viewBmp);
bmpDrawable.setBounds(0, 0,bmpDrawable.getIntrinsicWidth(),bmpDrawable.getIntrinsicHeight());
// create and set imagespan
ssb.setSpan(new ImageSpan(bmpDrawable),x ,x + c.length() , Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
x = x+ c.length() +1;
}
// set chips span
setText(ssb);
// move cursor to last
setSelection(getText().length());
}
}
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
setChips(); // call generate chips when user select any item from auto complete
}
// this method set country flag image in textview's drawable component, this logic is not optimize, you need to change as per your requirement
public void setFlags(TextView textView,String country){
country = country.trim();
if(country.equals("India")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.india, 0);
}
else if(country.equals("United States")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.unitedstates, 0);
}
else if(country.equals("Canada")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.canada, 0);
}
else if(country.equals("Australia")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.australia, 0);
}
else if(country.equals("United Kingdom")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.unitedkingdom, 0);
}
else if(country.equals("Philippines")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.philippines, 0);
}
else if(country.equals("Japan")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.japan, 0);
}
else if(country.equals("Italy")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.japan, 0);
}
else if(country.equals("Germany")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.germany, 0);
}
else if(country.equals("Russia")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.russia, 0);
}
else if(country.equals("Malaysia")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.malaysia, 0);
}
else if(country.equals("France")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.france, 0);
}
else if(country.equals("Sweden")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.sweden, 0);
}
else if(country.equals("New Zealand")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.newzealand, 0);
}
else if(country.equals("Singapore")){
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.singapore, 0);
}
}
}
Step 5 : Create drawable shape for chip named "chips_edittext_bg.xml" in drawable folder.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke
android:width="1dp"
android:color="#A6B0B8" />
<solid android:color="#E5E5E6" />
<corners
android:bottomLeftRadius="3dp"
android:bottomRightRadius="3dp"
android:topLeftRadius="3dp"
android:topRightRadius="3dp" >
</corners>
</shape>
Step 6 : Create TextView layout for chip named "chips_edittext.xml" in layout folder
<?xml version="1.0" encoding="UTF-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/edtTxt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/chips_edittext_gb"
android:drawablePadding="2dp"
android:drawableRight="@drawable/android"
android:padding="8dp"
android:shadowColor="#FFFFFF"
android:shadowDy="1"
android:shadowRadius="0.01"
android:textColor="#000000"
android:textSize="18sp"
android:textStyle="bold" />
Step 7 : Create string array for multi select data named "country" in strings.xml
<string-array name="country">
<item >India</item>
<item>United States</item>
<item>Canada</item>
<item>Australia</item>
<item>United Kingdom</item>
<item>Philippines</item>
<item >Japan</item>
<item>Italy</item>
<item>Germany</item>
<item>Russia</item>
<item>Malaysia</item>
<item>France</item>
<item>Sweden</item>
<item>New Zealand</item>
<item>Singapore</item>
</string-array>
Step 8 : Edit layout of main_activity.xml file
<RelativeLayout 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"
tools:context=".MainActivity" >
<com.kpbird.chipsedittext.ChipsMultiAutoCompleteTextview
android:id="@+id/multiAutoCompleteTextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:ems="10"
/>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="@+id/multiAutoCompleteTextView1"
android:onClick="buttonClicked"
android:text="@string/getvalue" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="@+id/button1"
android:text="@string/selectedcountries"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
Step 9 : Edit code of mainactivity.java file
package com.kpbird.chipsedittext;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.MultiAutoCompleteTextView;
import android.widget.TextView;
public class MainActivity extends Activity {
ChipsMultiAutoCompleteTextview mu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mu = (ChipsMultiAutoCompleteTextview) findViewById(R.id.multiAutoCompleteTextView1);
String[] item = getResources().getStringArray(R.array.country);
Log.i("", "Country Count : " + item.length);
mu.setAdapter(new ArrayAdapter(this,
android.R.layout.simple_dropdown_item_1line, item));
mu.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
}
public void buttonClicked(View v) {
TextView tv = (TextView) findViewById(R.id.textView1);
tv.setText(mu.getText().toString());
}
}
Source code : Github Link



Looking forward to it.
ReplyDeleteHello sir, i have small doubt that i need to display contact name but while retrieving values from it they should be a contact numbers. Please help me how to solve this ?
ReplyDeleteHello Ramesh,
ReplyDeleteChips Edit Text is extension of MultiAutoCompleteTextView. It does not support key value.
To solve your problem I can suggest two solution
1. Take separate ArrayList and put numbers in it when user select contact.
2. You can use setTag(key,value) property of MutliAutoCompleteTextView.
REF :http://developer.android.com/reference/android/view/View.html#setTag(int, java.lang.Object)
I hope above reply help you to solve your problem.
Thank You
KPBird
Thank you for your reply.If i want to use this "contact1 and contact2 are now friends." but now i send to server ids instead of names, then how could i solve this ? I tried with following url but i didn't succeed much. https://android.googlesource.com/platform/packages/apps/Mms/+/refs/heads/master/src/com/android/mms/ui/RecipientsEditor.java . And more thing i run your code i got an error when i enter first character is comma,fix it and i hope it will helpful to perfection in your code .
ReplyDeleteAwesome (Y)
ReplyDeleteHello, That's a great code, But I have small problem with it. I want to touch to image in chip to delete this chip from TextView but it is hard to catch onChipTouchEvent. Could you please support me sir?
ReplyDeleteThanks && bestRegards,
Hello Vidao,
ReplyDeleteTo capture click Android provide ClicableSpan.
Reference link :
1. http://developer.android.com/reference/android/text/style/ClickableSpan.html
2. http://thanksmister.com/tag/clickablespan/
Thank You
Oh, Thanks you very much.
ReplyDeleteI solved my problem.
I think in your lib may be you should write remove chip method, it is very helpful for some person like me.
Thanks && BestRegards,
Dear, I set more span in the SpannableStringBuilder to get ClickableSpan. It is worked in android 2.3.3 or higher but in android 2.2 it appear duplicate chip in each text insert. Ex: when I edit "France" complete with "," The Image of chip is "'Iamge'France 'Image'France," and the getText() still return "France,". Could you please give me some idea sir.
ReplyDeleteThanks you very much,