Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Autocomplete

I'm still a newbie in Android and I'm trying to work my way around autocomplete textboxes. I'm using a MultiAutoCompleteTextView to fill a text box and provide hints from an array of strings. Each string in the array is the name of an object that has an id. So, my question is twofold:

  • After the user clicks on a given entry on the auto-complete, how can I find the id that corresponds to the string chosen by the user?

  • Is it somehow possible to create a "Facebook-like box" around the item that is chosen from the autocomplete list, which work like atomic units that the user can delete by pressing an X? (similar to what happens in every tag on the tag box here in stackoverflow)

Thanks in advance

like image 643
Sagito Avatar asked Jan 17 '23 05:01

Sagito


2 Answers

Android has the source code for the "Chips" widgets which are used in the Mail app. They are the chips that represent users that are recipients of the message. And they look just like the Facebook widgets you're referring to: a name with an "X" to cancel. I was able to tweak the code and make it usable for my own needs but to be honest its really complex and it took my a long time to wrap my head around it.

The core principle is that you use Spannable strings and draw the bitmaps for the background and the "X" manually.

Here is the android source code: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/com/android/ex/chips/RecipientEditTextView.java

The core methods are createSelectedChip, constructChipSpan.

like image 163
Cody Caughlan Avatar answered Jan 25 '23 09:01

Cody Caughlan


I open-sourced a TokenAutoComplete on github that solves this pretty well. There doesn't seem to be a simpler answer out there. Here's a basic implementation of what you describe:

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.getName());

        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'll need to find your own x drawable)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:background="@drawable/token_background">
    <TextView android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/white"
        android:textSize="14sp"
        android:text="Test Me"
        android:padding="2dp" />

    <ImageView
        android:layout_height="10dp"
        android:layout_width="10dp"
        android:src="@drawable/x"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="3dp"
        android:layout_marginRight="5dp" />
</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", "[email protected]"),
                new Person("Margaret Smith", "[email protected]"),
                new Person("Max Jordan", "[email protected]"),
                new Person("Meg Peterson", "[email protected]"),
                new Person("Amanda Johnson", "[email protected]"),
                new Person("Terry Anderson", "[email protected]")
        };

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

        completionView = (ContactsCompletionView)findViewById(R.id.searchView);
        completionView.setAdapter(adapter);
        completionView.setTokenClickStyle(TokenCompleteTextView.TokenClickStyle.Delete);
    }
}

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>

Here's the interface you get:

Image of working TokenAutoComplete activity

like image 25
Marshall Weir Avatar answered Jan 25 '23 10:01

Marshall Weir