Contact Bubble EditText

AndroidAndroid EdittextDrawableHtml

Android Problem Overview


I am trying to create contact bubbles in the MultiAutoCompleteTextView similiar to how it is implemented in the Google+ app. Below is a screen shot:

![Google+ Compose Post Screenshot][1] [1]: http://i.stack.imgur.com/clY7U.png

.

I have tried to extend the DynamicDrawableSpan class in order to get a spannable drawable in the background of a span of text

public class BubbleSpan extends DynamicDrawableSpan {
  private Context c;

  public BubbleSpan(Context context) {
    super();
    c = context;
  }

  @Override
  public Drawable getDrawable() {
    Resources res = c.getResources();
    Drawable d = res.getDrawable(R.drawable.oval);
    d.setBounds(0, 0, 100, 20);
    return d;
  }
}

Where my oval.xml drawable is defined as so:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
  <solid android:color="#352765"/>
  <padding android:left="7dp" android:top="7dp"
    android:right="7dp" android:bottom="7dp" />
  <corners android:radius="6dp" />
</shape>

In my Activity class that has the MulitAutoCompleteTextView, I set the bubble span like so:

final Editable e = tv.getEditableText();
final SpannableStringBuilder sb = new SpannableStringBuilder();
sb.append("some sample text");
sb.setSpan(new BubbleSpan(getApplicationContext()), 0, 6, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
e.append(sb); 

However, instead of the oval shape displaying behind the first 6 characters in the string, the characters are not visible and there is no oval drawable in the background.

If i change the BubbleSpan's getDrawable() method to use a .png instead of a shape drawable:

public Drawable getDrawable() {
  Resources res = c.getResources();
  Drawable d = res.getDrawable(android.R.drawable.bottom_bar);
  d.setBounds(0, 0, 100, 20);
  return d;
}

Then the .png will show up but the characters in the string that are a part of the span will not show up. How can I make it so that the characters in the span are displayed in the foreground, meanwhile a custom shape drawable gets displayed in the background?

I attempted to also use an ImageSpan instead of subclassing DynamicDrawableSpan but was unsuccessful.

Android Solutions


Solution 1 - Android

Thanks @chrish for all the help. So here is how i did it:

final SpannableStringBuilder sb = new SpannableStringBuilder();
TextView tv = createContactTextView(contactName);
BitmapDrawable bd = (BitmapDrawable) convertViewToDrawable(tv);
bd.setBounds(0, 0, bd.getIntrinsicWidth(),bd.getIntrinsicHeight());

sb.append(contactName + ",");
sb.setSpan(new ImageSpan(bd), sb.length()-(contactName.length()+1), sb.length()-1,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
to_input.setText(sb);

public TextView createContactTextView(String text){
  //creating textview dynamically
  TextView tv = new TextView(this);
  tv.setText(text);
  tv.setTextSize(20);
  tv.setBackgroundResource(R.drawable.oval);
  tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_clear_search_api_holo_light, 0);
  return tv;
}

public static Object convertViewToDrawable(View view) {
  int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
  view.measure(spec, spec);
  view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
  Bitmap b = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
            Bitmap.Config.ARGB_8888);
  Canvas c = new Canvas(b);
  c.translate(-view.getScrollX(), -view.getScrollY());
  view.draw(c);
  view.setDrawingCacheEnabled(true);
  Bitmap cacheBmp = view.getDrawingCache();
  Bitmap viewBmp = cacheBmp.copy(Bitmap.Config.ARGB_8888, true);
  view.destroyDrawingCache();
  return new BitmapDrawable(viewBmp);

}

Solution 2 - Android

Here is a complete Solution for you

//creating textview dynamicalyy
TextView textView=new TextView(context);
textview.setText("Lauren amos");
textview.setbackgroundResource(r.color.urovalshape);
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.icon_cross, 0);


BitmapDrawable dd = (BitmapDrawable) SmsUtil.getDrawableFromTExtView(textView);
edittext.settext(addSmily(dd));

//convert image to spannableString
public SpannableStringBuilder addSmily(Drawable dd) {
 dd.setBounds(0, 0, dd.getIntrinsicWidth(),dd.getIntrinsicHeight());
SpannableStringBuilder builder = new SpannableStringBuilder();
builder.append(":-)");
builder.setSpan(new ImageSpan(dd), builder.length() - ":-)".length(),builder.length(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

return builder;
}

  //convert view to drawable
  public static Object getDrawableFromTExtView(View view) {

	int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
	view.measure(spec, spec);
	view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
	Bitmap b = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
			Bitmap.Config.ARGB_8888);
	Canvas c = new Canvas(b);
	c.translate(-view.getScrollX(), -view.getScrollY());
	view.draw(c);
	view.setDrawingCacheEnabled(true);
	Bitmap cacheBmp = view.getDrawingCache();
	Bitmap viewBmp = cacheBmp.copy(Bitmap.Config.ARGB_8888, true);
	view.destroyDrawingCache();
	return new BitmapDrawable(viewBmp);

}

Here is the complete project file ,if any of you want to use Spannble

Solution 3 - Android

I got a library which does what you're looking for with :

  • Default or fully customizable (you can even use your own layout)
  • Multiline support
  • Click listener

Have a look here

Here a quickstart :

Add ChipView to your layout or create it programmatically :

<com.plumillonforge.android.chipview.ChipView
    android:id="@+id/chipview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

Init it with a list of data which extend abstract Chip and a click listener (if you want) :

List<Chip> chipList = new ArrayList<>();
chipList.add(new Tag("Lorem"));
chipList.add(new Tag("Ipsum dolor"));
chipList.add(new Tag("Sit amet"));
chipList.add(new Tag("Consectetur"));
chipList.add(new Tag("adipiscing elit"));
ChipView chipDefault = (ChipView) findViewById(R.id.chipview);
chipDefault.setChipList(chipList);
chipDefault.setOnChipClickListener(new OnChipClickListener() {
        @Override
        public void onChipClick(Chip chip) {
            // Action here !
        }
    });

Default ChipView is rendered like this :

Default ChipView

But you can customise as you like from overall to Chip level :

Overall ChipView Custom ChipView

This isn't a MultiAutocomplete but you can manage to mimic it (I'm actually using it like that)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEtienne LawlorView Question on Stackoverflow
Solution 1 - AndroidEtienne LawlorView Answer on Stackoverflow
Solution 2 - AndroidKrishna ShresthaView Answer on Stackoverflow
Solution 3 - AndroidPlumillon ForgeView Answer on Stackoverflow