Android MultiAutoCompleteTextView多选

在Android开发中,我们经常需要实现一个多选的功能,用户可以从一组选项中选择多个选项。而Android提供了一个非常方便的控件来实现这个功能,那就是MultiAutoCompleteTextView。

什么是MultiAutoCompleteTextView

MultiAutoCompleteTextView是Android上的一个可编辑的文本框控件,它继承自AutoCompleteTextView。它的特点是可以在用户输入的过程中显示一个下拉列表,用户可以从列表中选择一个或多个选项。另外,它还支持自定义的分隔符,可以让用户以更灵活的方式选择多个选项。

如何使用MultiAutoCompleteTextView

要使用MultiAutoCompleteTextView,首先需要在布局文件中添加一个MultiAutoCompleteTextView控件:

<MultiAutoCompleteTextView
    android:id="@+id/multiAutoCompleteTextView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

然后,在Activity或Fragment中获取MultiAutoCompleteTextView的实例,并设置适配器:

MultiAutoCompleteTextView multiAutoCompleteTextView = findViewById(R.id.multiAutoCompleteTextView);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
        android.R.layout.simple_dropdown_item_1line, data);
multiAutoCompleteTextView.setAdapter(adapter);

这里的data是一个字符串数组,存储了供用户选择的选项。

接下来,我们需要设置MultiAutoCompleteTextView的Tokenizer,Tokenizer负责确定文本框中哪些部分应该被视为一个完整的选项。通常情况下,我们使用一个简单的逗号作为分隔符:

multiAutoCompleteTextView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());

至此,一个基本的MultiAutoCompleteTextView就已经配置完成了。

实现多选功能

MultiAutoCompleteTextView默认是单选的,但我们可以通过自定义Tokenizer和适配器来实现多选的功能。

首先,我们需要自定义一个Tokenizer,用于确定文本框中哪些部分应该被视为一个完整的选项。在Tokenizer的findTokenStart方法中,我们可以根据自定义的分隔符来确定选项的起始位置。在findTokenEnd方法中,我们可以根据分隔符来确定选项的结束位置。在terminateToken方法中,我们可以对选项进行一些处理,比如去掉前后的空格。

public class MultiSelectionTokenizer implements MultiAutoCompleteTextView.Tokenizer {

    private char mSeparator = ';';

    public void setSeparator(char separator) {
        mSeparator = separator;
    }

    @Override
    public int findTokenStart(CharSequence text, int cursor) {
        int i = cursor;

        while (i > 0 && text.charAt(i - 1) != mSeparator) {
            i--;
        }
        while (i < cursor && text.charAt(i) == ' ') {
            i++;
        }

        return i;
    }

    @Override
    public int findTokenEnd(CharSequence text, int cursor) {
        int i = cursor;
        int len = text.length();

        while (i < len) {
            if (text.charAt(i) == mSeparator) {
                return i;
            } else {
                i++;
            }
        }

        return len;
    }

    @Override
    public CharSequence terminateToken(CharSequence text) {
        int i = text.length();

        while (i > 0 && text.charAt(i - 1) == ' ') {
            i--;
        }

        if (i > 0 && text.charAt(i - 1) == mSeparator) {
            return text;
        } else {
            if (text instanceof Spanned) {
                SpannableString sp = new SpannableString(text + String.valueOf(mSeparator));
                TextUtils.copySpansFrom((Spanned) text, 0, text.length(), Object.class, sp, 0);
                return sp;
            } else {
                return text + String.valueOf(mSeparator);
            }
        }
    }
}

然后,我们需要自定义一个适配器,用于显示选项列表和处理用户的选择。在适配器中,我们需要重写getView方法来自定义选项的展示样式,重写getFilter方法来实现自定义的过滤逻辑。

public class MultiSelectionAdapter extends ArrayAdapter<String> implements Filterable {

    private List<String> mOriginalData;
    private List<String> mFilteredData;

    public MultiSelectionAdapter(Context context, int resource, List<String> data) {
        super(context, resource, data);
        mOriginalData = data;
        mFilteredData = new ArrayList<>();
    }