54

enter image description hereCan someone please point me in the right direction how to do those bubbles or labels in the EditText something like those you see when you want to compose something in Stream for Google+ when you add a circle or contact? The Rectangle is an auto complete edittext.

Paresh Mayani
  • 127,700
  • 71
  • 241
  • 295
Maurice
  • 6,413
  • 13
  • 51
  • 76

8 Answers8

18

What you are showing is the same behavior as the SMS stock application. Search for the code here to see how it's done.

EDIT:

The code should be in platform_packages_apps_mms. Take a look at the RecipientsEditor class.

Macarse
  • 91,829
  • 44
  • 175
  • 230
  • @David: Check the sms application when you create a new sms. You will be able to pick between more than one. The sms code is open source. – Macarse Nov 15 '11 at 15:38
  • This was a pretty good link that lead me to read up on the MultiAutoCompleteTextView which kinda showed how the autocomplete portion works. The code describes that it is delimited by a "," or ";" but the above shows no delimiter and an image. The cool thing is when u press backspace on the "bubble" it deletes the whole word! Does the text have a background image in it or did I miss something? – Maurice Nov 17 '11 at 02:30
  • @Maurice: I would guess that's a `TextView` with a gray `android:background` and an `android:leftDrawable` – Macarse Nov 17 '11 at 11:01
  • From what I can tell, you need to use the `Spannable` system (which I describe in another answer) to get drawables into a `TextView`/`EditText` that flow as text. – Steve Pomeroy Nov 17 '11 at 13:08
  • Works on 4+ devices but not on 2.3... (Not tested on any 3) – madlymad May 15 '13 at 09:35
  • If anyone's interested, I've published a similar solution on GitHub: https://github.com/AndroidDeveloperLB/ChipsLibrary . – android developer Apr 07 '14 at 20:04
8

I built TokenAutoComplete on github to solve a similar problem and it should work for you as well. Here's a basic implementation of a demo app:

public class ContactsCompletionView extends TokenCompleteTextView {
    public ContactsCompletionView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected View getViewForObject(Object object) {
        Person p = (Person)object;

        LayoutInflater l = (LayoutInflater)getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        LinearLayout view = (LinearLayout)l.inflate(R.layout.contact_token, (ViewGroup)ContactsCompletionView.this.getParent(), false);
        ((TextView)view.findViewById(R.id.name)).setText(p.getEmail());

        return view;
    }

    @Override
    protected Object defaultObject(String completionText) {
        //Stupid simple example of guessing if we have an email or not
        int index = completionText.indexOf('@');
        if (index == -1) {
            return new Person(completionText, completionText.replace(" ", "") + "@example.com");
        } else {
            return new Person(completionText.substring(0, index), completionText);
        }
    }
}

Layout code for contact_token (you can use any kind of layout here or could throw an ImageView in if you want images in the token)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content">

    <TextView android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/token_background"
        android:padding="5dp"
        android:textColor="@android:color/white"
        android:textSize="18sp" />

</LinearLayout>

Token backgound drawable

<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="#ffafafaf" />
    <corners
        android:topLeftRadius="5dp"
        android:bottomLeftRadius="5dp"
        android:topRightRadius="5dp"
        android:bottomRightRadius="5dp" />
</shape>

Person object code

public class Person implements Serializable {
    private String name;
    private String email;

    public Person(String n, String e) { name = n; email = e; }

    public String getName() { return name; }
    public String getEmail() { return email; }

    @Override
    public String toString() { return name; }
}

Sample activity

public class TokenActivity extends Activity {
    ContactsCompletionView completionView;
    Person[] people;
    ArrayAdapter<Person> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        people = new Person[]{
                new Person("Marshall Weir", "marshall@example.com"),
                new Person("Margaret Smith", "margaret@example.com"),
                new Person("Max Jordan", "max@example.com"),
                new Person("Meg Peterson", "meg@example.com"),
                new Person("Amanda Johnson", "amanda@example.com"),
                new Person("Terry Anderson", "terry@example.com")
        };

        adapter = new ArrayAdapter<Person>(this, android.R.layout.simple_list_item_1, people);

        completionView = (ContactsCompletionView)findViewById(R.id.searchView);
        completionView.setAdapter(adapter);
    }
}

Layout code

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.tokenautocomplete.ContactsCompletionView
        android:id="@+id/searchView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>
Marshall Weir
  • 463
  • 5
  • 10
4

I solved this HERE Contact Bubble EditText

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

}

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;
}
Community
  • 1
  • 1
Etienne Lawlor
  • 6,817
  • 18
  • 77
  • 89
  • the above image does not have any delimiter....is it possible to have an empty delimiter instead of using ","..I tried without giving any tokenizer but the multiautocompletetextview does not show any suggestions.. – VijayRaj Aug 26 '13 at 10:57
4

You can do this by creating a subclass of android.text.style.DynamicDrawableSpan. ImageSpan is an example of this: it replaces a span (range) of text with an image.

This example will put an a star in an edit field, replacing the text "test". Create an EditText in your layout with the id of "text" and put this in onCreate() (or wherever):

    EditText mText = (EditText) findViewById(R.id.text);
    final Editable e = mText.getEditableText();
    final SpannableStringBuilder sb = new SpannableStringBuilder();
    sb.append("test");
    sb.setSpan(new ImageSpan(this, android.R.drawable.btn_star), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    e.append(sb);

I didn't see any classes that looked like they could wrap normal text in a drawable, but that could be pretty easily solved by overriding the getDrawable() method and rendering the text yourself.

Steve Pomeroy
  • 10,071
  • 6
  • 34
  • 37
  • This was interesting. You are able to put the image in the edittext but you have to backspace 4 times to delete the whole image. – Maurice Nov 17 '11 at 02:43
  • I suspect the "Your circles" in the above is "Your circles," in text but covered by an image as described in this answer. Now to figure out how to delete the whole text when you delete the delimiter.... – Maurice Nov 17 '11 at 03:18
  • The backspacing a few times actually depends on the Spannable.SPAN_INCLUSIVE_EXCLUSIVE part of the span. Try playing around with a few different settings - there are 4 total. – Steve Pomeroy Nov 17 '11 at 13:04
  • As far as the "your circles" in text, you're probably right. You can also add extra information into the flow of your text using the `Annotation` class that was pointed to in Macarse's answer. I suspect the final answer would use both classes. – Steve Pomeroy Nov 17 '11 at 13:11
  • All 4 don't work, just tried it. I'm guessing it has something to do with a textwatcher. – Maurice Nov 18 '11 at 06:10
  • Ah. Then it was probably an issue with where the span was. I made some revisions to the sample code in my answer, so perhaps you have an earlier revision. Make sure that the span ranges from 0 to 4. I'll post a complete set of working code in a moment. – Steve Pomeroy Nov 20 '11 at 04:52
  • Here's the class: http://staticfree.info/clip/2011-11-19T235307 and the layout http://staticfree.info/clip/2011-11-19T235336 – Steve Pomeroy Nov 20 '11 at 04:54
  • Very cool. Now we just got to figure out how to display the text with a picture and integrate it with the MultiAutoCompleteTextView. – Maurice Nov 22 '11 at 01:46
  • This ImageSpan looks like it replaces a span of text. How do you create a custom background span, so that you can see the text on top, just like the Google+ app works? – Etienne Lawlor May 29 '12 at 00:10
  • try a 9-patch with a content area defined. – Steve Pomeroy May 30 '12 at 22:24
  • @StevePomeroy, how can you have multiple 9-patch images in an EditText view like the MultiAutoCompleteTextView? also how would you convert text into a 9 patch image? – Etienne Lawlor May 31 '12 at 07:58
  • The idea is that you'd use a 9-patch for an ImageSpan background. I'm not sure if it'd work (I never was able to get text on top of an image like this question is asking without needing to draw the text myself) – Steve Pomeroy Jun 01 '12 at 17:01
0

If you mean the hints, you can add the simply with:

android:hint="@string/myHint"

This will put the grey label in the EditText when it is empty.

brianestey
  • 8,202
  • 5
  • 33
  • 48
0

To set the circle icon in the left of the EditText you can change the leftDrawable.

You can do it on the layout xml file android:drawableRight="@drawable/search_icon" or programmatically using the setCompoundDrawablesWithIntrinsicBounds function.

If you also want to give the bubble style, you must change the backgroud drawable by a 9-patch that have the style. here you have a tutorial for a 9-patch bubble for google maps.

Hope it helped! :)

Macarse
  • 91,829
  • 44
  • 175
  • 230
Jordi Coscolla
  • 1,066
  • 6
  • 8
0

I think it use setCompoundDrawables() method to insert that picture inside edit text

Kiran Babu
  • 1,893
  • 2
  • 13
  • 7
  • That was already suggested in Jordi's answer, but that kind of drawable doesn't flow with the text as the poster wants. – Steve Pomeroy Nov 20 '11 at 04:58
-1

I decided to give something back to the community and created library that is aimed to solve this exact problem You have. The library along with example project is availeable on GitHub: https://github.com/RafalManka/BubbleEditText

RafalManka
  • 366
  • 5
  • 14