5

我有 3 个 AutoCompleteTextView,我想在它们上注册 2 个 String[] 适配器。目前,我正在这样做:

atw_from.setAdapter(new ArrayAdapter(ctx, android.r.layout.simple_dropdown_item_1line, stages_adapter));

假设我的用户想要输入“Középmező”,他开始输入“Közé”,然后他会被要求选择 Középmező,在此之前,这非常简单。但是如果用户懒得输入重音符号(而且很多人都很懒惰),因此他只会输入 Kozepmezo,那么他将不会得到任何报价,因为我的 String[] 中没有 Kozepmezo。我想要的是,如果他输入“Koze”,则应该向他提供 Középmező,因此即使他不使用重音,也总是会为他提供带有重音的实际单词。

目前,我有一个非常愚蠢的解决方案,我有一个字符串 [],其大小是原始 [] 的两倍,前半部分包含带重音的单词,第二部分包含非重音版本。所以现在,如果他输入 Közé,他将获得 Középmező,如果他输入 Koze,他将获得 Kozepmezo。它之所以有效,是因为服务器可以处理这两个版本,但它看起来很傻,我想解决它。

据我了解,我应该制作一个完整的自定义适配器。这是最好的方法,还是 SDK 中包含任何解决方案?如果我应该制作自定义适配器,谁能指出我正确的方向,如何做到这一点?:)

编辑:添加了我自己的答案,应该对每个人都有效,为其他答案欢呼,这将我引向了好的方向!

4

3 回答 3

1

我确实会选择一个自定义适配器,您可以在其中提供自己的过滤器功能来匹配重音符号和非重音符号。

可以在此处找到执行此操作的示例实现。基本上,您将需要在其中实现实际的过滤performFiltering-我假设您已经有一种方法可以消除查询,因为您当前正在String[]使用消除的版本填充您的查询。您需要将带和不带重音的查询与数组中的条目(您希望使用带和不带重音的条目)进行比较。最后你应该至少有以下四个测试:

accented(query) -> accented(entry)
accented(query) -> deaccented(entry)
deaccented(query) -> accented(entry)
deaccented(query) -> deaccented(entry)

通过动态去重音,您只需要提供String[]带有重音的词,而过滤逻辑(在您的适配器中)将负责匹配(去)重音词。

编辑:正如所讨论的,下面是我正在进行的项目之一的示例实现。

一些指示:

  1. CustomArrayAdapter主要是简化常见任务的包装类;例如与行包装器/视图持有者的交互。基本上它所需要的只是一个构造函数和实现updateRow(显然会从超类的getView方法中调用)。
  2. CustomRowWrapper应该很简单。
  3. ArrayUtilArrayUtil.FilterFuction注意实际的过滤。简单地说,这些充当了 for 循环的替代品,该循环构建了一个新列表,其中包含符合某些条件的所有项目。

public class CARMedicationSuggestionAdapter extends CustomArrayAdapter<CARMedicationInfo, RowWrapper> {

    private List<CARMedicationInfo> mMedications;
    private Filter mFilter;

    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
     * constructor
     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    public CARMedicationSuggestionAdapter(Context context, List<CARMedicationInfo> objects) {
        super(RowWrapper.class, context, R.layout.medication_suggestion_item_layout, objects);
        // keep copy of all items for lookups 
        mMedications = new ArrayList<CARMedicationInfo>(objects);
    }

    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
     * update row
     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    @Override protected void updateRow(RowWrapper wrapper, CARMedicationInfo item) {
        wrapper.getNameTextView().setText(item.toString());
    }

    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
     * get filter
     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    @Override public Filter getFilter() {
        // return if already created
        if (mFilter != null) return mFilter;
        mFilter = new Filter() {
            @Override protected void publishResults(CharSequence constraint, FilterResults results) {
                @SuppressWarnings("unchecked") List<CARMedicationInfo> filtered = (List<CARMedicationInfo>) results.values;
                if (results == null || results.count == 0) return;
                // clear out current suggestions and add all new ones
                clear(); 
                addAll(filtered);
            }

            @Override protected FilterResults performFiltering(final CharSequence constraint) {
                // return empty results for 'null' constraint
                if (constraint == null) return new FilterResults();
                // get all medications that contain the constraint in drug name, trade name or whose string representation start with the constraint
                List<CARMedicationInfo> suggestions = ArrayUtil.filter(mMedications, new ArrayUtil.FilterFunction<CARMedicationInfo>() {
                    @Override public boolean filter(CARMedicationInfo item) {
                        String query = constraint.toString().toLowerCase().trim();
                        return  item.mMedicationDrugName.toLowerCase().contains(query) || 
                                item.mMedicationTradeName.toLowerCase().contains(query) ||
                                item.toString().toLowerCase().startsWith(query); 
                    }
                });
                // set results and size
                FilterResults filterResults = new FilterResults();
                filterResults.values = suggestions;
                filterResults.count = suggestions.size();
                return filterResults;
            }
        };
        return mFilter;
    }

    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
     * row wrapper
     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    static class RowWrapper extends CustomRowWrapper {

        private ImageView mIconImageView;
        private TextView mNameTextView;

        public RowWrapper(View row) {
            super(row);
        }

        public ImageView getIconImageView() {
            if (mIconImageView == null) mIconImageView = (ImageView) mRow.findViewById(R.id.icon_imageview);
            return mIconImageView;
        }

        public TextView getNameTextView() {
            if (mNameTextView == null) mNameTextView = (TextView) mRow.findViewById(R.id.name_textview);
            return mNameTextView;
        }

    }

}
于 2012-04-04T19:38:27.063 回答
1

好吧,在处理这个问题时经历了很多痛苦之后,这就是我最后所做的事情。这根本不是一个好习惯,我可能做错了,但至少现在它工作得很好。

简单地说 ctrl+c, ctrl+v 是BaseAdapter的源代码, ctrl+c, ctrl+v 是ArrayAdapter的源代码。现在看看私有内部类 ArrayFilter,尤其是 performFiltering 方法。修改(而不是覆盖!)它,就像你想要的那样,在我的例子中,我添加了很多 .replace("x","y") 东西,用于去重音部分。

无论我尝试了什么其他方法,要么会产生不可预测的强制关闭(很多,而且完全随机),要么我就是不能这样做,因为太多的方法/变量是私有的,而不是受保护的。我必须说,谷歌应该重新审视这些代码......

注意:你真的不需要 ctrl+c ctrl+v BaseAdapter 代码,因为它是一个公共抽象类,但是,它不是那么多代码,这样一切都在那里,对你清晰可见.

干杯

于 2012-04-10T09:26:34.473 回答
0

看看这个线程remove-accents-from-string和 android Normalizer

[编辑] 或者您可以尝试使用两个数组的合并适配器

于 2012-04-01T14:03:59.143 回答