Contact Bubble EditText
Asked Answered
H

4

91

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 .

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.

Harrisharrisburg answered 30/5, 2012 at 8:4 Comment(3)
possible duplicate of Android Labels or Bubbles in EditTextSupersensible
How you are getting selected contact numbersPerice
github.com/splitwise/TokenAutoComplete could be helpful to someOrtensia
H
55

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);

}
Harrisharrisburg answered 2/6, 2012 at 17:45 Comment(5)
I found that this didn't work in all devices due to scaling issues. A better way to do this is to return the bitmap from the convertView, then use the actual bitmap's dimensions when setting the drawable edges. E.g. BitmapDrawable bd = new BitmapDrawable(bitmap); bd.setBounds(0,0,bitmap.getWidth(), bitmap.getHeight()); That works in all devices.Macromolecule
Hi, I may need to post this in a new question, but wanted to know whether you encountered problems with multi line TextViews. I'm running this on Android 3.2 and "sometimes", it looks like the width of the bubble is not calculated well. As in the text will not continue to the next line, but instead continue outside of the TextView. If you have seen this, any tips?Propriety
If the text with bubble is wider that autocomplete than the bubble is created twice in two rows. You shold set this to textView: textView.setMaxWidth(this.getWidth() - SOME_PADDING);` And I'am also using this (if text is too large is in two lines in bubble and with ... at the end): textView.setEllipsize(TruncateAt.END); textView.setSingleLine(false); textView.setMaxLines(2);Buckle
this works fine wn u select from dropdown list. In case, if u want set some predefined values to edittext, then , how can i wrap that text with border n cross button?Haitian
how you add the clicklistener to the different item in the textview to delete the text.Zacek
S
21

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

Shuffle answered 31/5, 2012 at 10:4 Comment(4)
thanks... your solution works fine but my issues is when i pressed ADD button bubble-text is add in edit-text but when i Clear edit-text and trying to re-enter(press Add button) previously added bubble is remaining and new one is appended too. and i also remove bubble when press right side cross sign.Tipstaff
Addressing first issue.i guess you stored text in list and you didn't clear while clearing Edit text. i may nt be wright, it was only a guess as i dont kno how you code.Shuffle
I know its an old post, but i need answer to my question..I am building same application as shown above..i m using MultiAutoCompleteTextView for the suggestions and then create the bubbles when the item is clicked..the bubbles are created successfully but my problem is I don't want the cursor to appear between the two bubbles...I m using space tokenizer for MultiAutoCompleteTextView..any clue how to achieve this??Chihuahua
@chrish Thanks for this code, I have one question nevertheless. I have a situation where I have some values already with me, and I will paste them directly into the edit text as spannable texts. however, now I just wonder that is it possible to combine your code from spannable project with this kind of functionality. I want to have an ability to add delete names at run time, adding may happen in bunch, however delete is as usual (one by one) .. thanksTripoli
D
5

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)

Dyeline answered 29/9, 2015 at 15:1 Comment(0)
B
2

Material https://material.io/components/chips/android#using-chips

The answers above are deprecated

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

and then in code:

val chip = Chip(context)
chip.text = text
chip.chipBackgroundColor =
ContextCompat.getColorStateList(
    requireContext(),
    R.color.color_sky_blue
)
chip.setOnCloseIconClickListener {
    //clicking close
}
chip.isCloseIconVisible = true
chip.closeIcon =
ContextCompat.getDrawable(requireContext(), R.drawable.ic_cross_chip)
chip.closeIconTint = ContextCompat.getColorStateList(requireContext(), R.color.colorAzure)
chip.closeIconSize = requireContext().resources.getDimension(R.dimen.dp12)
chip.setTextAppearance(R.style.ChipTextAppearance)
chipGroup.addView(chip)
Buller answered 6/7, 2022 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.