Android - 使用 AutoCompleteTextView 检测“@”旁边的单词

Android - Using AutoCompleteTextView to detect a word next to `@`

首先,我真的是 AutoCompleteTextView 的新手,从标题可以推断,我想将它用于我目前正在开发的社交媒体应用程序中的 Tag 人。

首先,我创建了一个名为 TagList 的 class 来包含名为 TagModel 的模型 class 列表:

public class TagModel {
    public String user_avatar;
    public String user_name;

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

这是整个适配器 class :

public class TagAdapter extends ArrayAdapter<TagModel> implements Filterable {

    private Context context;
    private int resource;
    private TagList mDataset;

    public TagAdapter(Context context, int resource) {
        super(context, resource);
        this.context = context;
        this.resource = resource;
        this.mDataset = new TagList();
    }

    public void changeItem(TagList tagList){
        this.mDataset.tagModelList.clear();
        notifyDataSetChanged();
        this.mDataset.tagModelList.addAll(tagList.tagModelList);
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return mDataset.tagModelList.size();
    }

    @Override
    public TagModel getItem(int position) {
        return this.mDataset.tagModelList.get(position);
    }

    @Override
    public Filter getFilter() {
        Filter myFilter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                ArrayList<TagModel> tempTagModel = new ArrayList<TagModel>();
                if(constraint != null) {
                    int length = mDataset.tagModelList.size();
                    int i = 0;
                    while(i<length){
                        TagModel item = mDataset.tagModelList.get(i);
                        //do whatever you wanna do here
                        //adding result set output array

                        tempTagModel.add(item);

                        i++;
                    }
                    //following two lines is very important
                    //as publish result can only take FilterResults objects
                    filterResults.values = tempTagModel;
                    filterResults.count = tempTagModel.size();
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence contraint, Filter.FilterResults results) {
                if(results != null && results.count > 0) {
                    notifyDataSetChanged();
                }
                else {
                    notifyDataSetInvalidated();
                }
            }
        };
        return myFilter;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        try{
            if(convertView==null){
                // inflate the layout
                LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(resource, parent, false);
            }

            TagModel objectItem = mDataset.tagModelList.get(position);

            ImageView userAvatar = (ImageView) convertView.findViewById(R.id.popup_tag_avatar);

            OpenSansFont userName = (OpenSansFont) convertView.findViewById(R.id.popup_tag_name);
            userName.setText(objectItem.user_name);

        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return convertView;

    }
}

我添加了单个虚拟数据来测试 AutoComplete 是否有效,嗯,它有效,但现在我在过滤方面不知所措 @(someone's name) 因为无论我输入什么,它都会显示我在列表中的虚拟数据。

我实际上需要在这里完成两件事,

  1. 获取过滤器以仅过滤@(某人的姓名)并将查询放入API.

  2. 当用户按下 space 时停止自动完成。

任何人都可以指出我正确的方向吗?我很乐意提供解释我的问题所需的任何代码..

更新:AutoCompleteTextView 上的一个有缺陷的 TextWatcher,试图获取 @ 之后和 " ".

之前的任何文本
tagAutoComplete.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

            if (count > 0) {
                if (before == 0) {
                    flag = false;
                    stringBuilder.replace(0, stringBuilder.length() - 1, "");
                }

                if (flag) {
                    stringBuilder.append(s.toString().charAt(count - 1));
                    FriendTagListShowAPI friendTagListShowAPI = new FriendTagListShowAPI();
                    friendTagListShowAPI.query.tag = stringBuilder.toString();
                    friendTagListShowAPI.query.user_id = userId;

                    FriendTagListShowAPIFunc friendTagListShowAPIFunc = new FriendTagListShowAPIFunc();
                    friendTagListShowAPIFunc.delegate = TestAutoComplete.this;
                    friendTagListShowAPIFunc.execute(friendTagListShowAPI);
                }

                if (before < s.length() && String.valueOf(s.charAt(before)).equals("@")) {
                    flag = true;
                }
            }
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });

你有两件事要做:

  1. 检测包含@someone.
  2. 的字符串
  3. 使用不带'@'字符的字符串作为某人进行查询

现在,您可以像 link Multiautocompletetextview, Show autocomplete drop down only when user presses a key after '@' key (like mention in FB app)

请向下滚动找到@Phuong Sala 的答案。如果你想多人联机,那就用MultiAutoCompleteTextView吧。

如果有帮助请告诉我

最后,我用了一个SO里找到的Tokenizer,但是忘了是从哪里找到的,sorry!

代码如下:

    multiAutoCompleteTextView.setTokenizer(new MultiAutoCompleteTextView.Tokenizer() {

        @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) == ' ') {
                return text;
            } else {
                if (text instanceof Spanned) {
                    SpannableString sp = new SpannableString(text + " ");
                    TextUtils.copySpansFrom((Spanned) text, 0, text.length(), Object.class, sp, 0);
                    return sp;
                } else {
                    return text + " ";
                }
            }
        }

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

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

            //Check if token really started with @, else we don't have a valid token
            if (i < 1 || text.charAt(i - 1) != '@') {
                return cursor;
            }

            return i;
        }

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

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

            return len;
        }
    });