AutoCompleteTextView 中的变音符号/国际字符

发布于 2024-10-15 12:58:14 字数 242 浏览 7 评论 0原文

我有一个(数组)列表

Car
Something
Šibica
Čavao
Cavao

有没有办法“强制”AutoCompleteTextView,这样如果用户输入字母“c”

Car
Čavao
Cavao

,它就会显示标准字母和国际字母 >(C 和 Č/Ć、S 和 Š、Z 和 Ž、D 和 Đ)。

I have a (array) list

Car
Something
Šibica
Čavao
Cavao

Is there a way to "force" AutoCompleteTextView so if user type in letter "c" it would show

Car
Čavao
Cavao

so it would show standard letter and international letter (C and Č/Ć, S and Š, Z and Ž, D and Đ).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

风苍溪 2024-10-22 12:58:14

使用此类作为ArrayAdapter(在本例中它用于 HR,但它可以用于任何角色)。

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Changes for Croatian language done by Stevica Kuharski, IT4U
 * Web: http://www.it4u.com.hr/en
 * E-mail: [email protected] 
 */

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Comparator;
import java.util.Collections;

/**
 * A ListAdapter that manages a ListView backed by an array of arbitrary
 * objects.  By default this class expects that the provided resource id references
 * a single TextView.  If you want to use a more complex layout, use the constructors that
 * also takes a field id.  That field id should reference a TextView in the larger layout
 * resource.
 *
 * However the TextView is referenced, it will be filled with the toString() of each object in
 * the array. You can add lists or arrays of custom objects. Override the toString() method
 * of your objects to determine what text will be displayed for the item in the list.
 *
 * To use something other than TextViews for the array display, for instance, ImageViews,
 * or to have some of data besides toString() results fill the views,
 * override {@link #getView(int, View, ViewGroup)} to return the type of view you want.
 */
public class HRArrayAdapter<T> extends BaseAdapter implements Filterable {
    /**
     * Contains the list of objects that represent the data of this ArrayAdapter.
     * The content of this list is referred to as "the array" in the documentation.
     */
    private List<T> mObjects;

    /**
     * Lock used to modify the content of {@link #mObjects}. Any write operation
     * performed on the array should be synchronized on this lock. This lock is also
     * used by the filter (see {@link #getFilter()} to make a synchronized copy of
     * the original array of data.
     */
    private final Object mLock = new Object();

    /**
     * The resource indicating what views to inflate to display the content of this
     * array adapter.
     */
    private int mResource;

    /**
     * The resource indicating what views to inflate to display the content of this
     * array adapter in a drop down widget.
     */
    private int mDropDownResource;

    /**
     * If the inflated resource is not a TextView, {@link #mFieldId} is used to find
     * a TextView inside the inflated views hierarchy. This field must contain the
     * identifier that matches the one defined in the resource file.
     */
    private int mFieldId = 0;

    /**
     * Indicates whether or not {@link #notifyDataSetChanged()} must be called whenever
     * {@link #mObjects} is modified.
     */
    private boolean mNotifyOnChange = true;

    private Context mContext;    

    private ArrayList<T> mOriginalValues;
    private HRArrayFilter mFilter;

    private LayoutInflater mInflater;

    /**
     * Constructor
     *
     * @param context The current context.
     * @param textViewResourceId The resource ID for a layout file containing a TextView to use when
     *                 instantiating views.
     */
    public HRArrayAdapter(Context context, int textViewResourceId) {
        init(context, textViewResourceId, 0, new ArrayList<T>());
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a layout to use when
     *                 instantiating views.
     * @param textViewResourceId The id of the TextView within the layout resource to be populated
     */
    public HRArrayAdapter(Context context, int resource, int textViewResourceId) {
        init(context, resource, textViewResourceId, new ArrayList<T>());
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param textViewResourceId The resource ID for a layout file containing a TextView to use when
     *                 instantiating views.
     * @param objects The objects to represent in the ListView.
     */
    public HRArrayAdapter(Context context, int textViewResourceId, T[] objects) {
        init(context, textViewResourceId, 0, Arrays.asList(objects));
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a layout to use when
     *                 instantiating views.
     * @param textViewResourceId The id of the TextView within the layout resource to be populated
     * @param objects The objects to represent in the ListView.
     */
    public HRArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects) {
        init(context, resource, textViewResourceId, Arrays.asList(objects));
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param textViewResourceId The resource ID for a layout file containing a TextView to use when
     *                 instantiating views.
     * @param objects The objects to represent in the ListView.
     */
    public HRArrayAdapter(Context context, int textViewResourceId, List<T> objects) {
        init(context, textViewResourceId, 0, objects);
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a layout to use when
     *                 instantiating views.
     * @param textViewResourceId The id of the TextView within the layout resource to be populated
     * @param objects The objects to represent in the ListView.
     */
    public HRArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects) {
        init(context, resource, textViewResourceId, objects);
    }

    /**
     * Adds the specified object at the end of the array.
     *
     * @param object The object to add at the end of the array.
     */
    public void add(T object) {
        if (mOriginalValues != null) {
            synchronized (mLock) {
                mOriginalValues.add(object);
                if (mNotifyOnChange) notifyDataSetChanged();
            }
        } else {
            mObjects.add(object);
            if (mNotifyOnChange) notifyDataSetChanged();
        }
    }

    /**
     * Inserts the specified object at the specified index in the array.
     *
     * @param object The object to insert into the array.
     * @param index The index at which the object must be inserted.
     */
    public void insert(T object, int index) {
        if (mOriginalValues != null) {
            synchronized (mLock) {
                mOriginalValues.add(index, object);
                if (mNotifyOnChange) notifyDataSetChanged();
            }
        } else {
            mObjects.add(index, object);
            if (mNotifyOnChange) notifyDataSetChanged();
        }
    }

    /**
     * Removes the specified object from the array.
     *
     * @param object The object to remove.
     */
    public void remove(T object) {
        if (mOriginalValues != null) {
            synchronized (mLock) {
                mOriginalValues.remove(object);
            }
        } else {
            mObjects.remove(object);
        }
        if (mNotifyOnChange) notifyDataSetChanged();
    }

    /**
     * Remove all elements from the list.
     */
    public void clear() {
        if (mOriginalValues != null) {
            synchronized (mLock) {
                mOriginalValues.clear();
            }
        } else {
            mObjects.clear();
        }
        if (mNotifyOnChange) notifyDataSetChanged();
    }

    /**
     * Sorts the content of this adapter using the specified comparator.
     *
     * @param comparator The comparator used to sort the objects contained
     *        in this adapter.
     */
    public void sort(Comparator<? super T> comparator) {
        Collections.sort(mObjects, comparator);
        if (mNotifyOnChange) notifyDataSetChanged();        
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
        mNotifyOnChange = true;
    }

    /**
     * Control whether methods that change the list ({@link #add},
     * {@link #insert}, {@link #remove}, {@link #clear}) automatically call
     * {@link #notifyDataSetChanged}.  If set to false, caller must
     * manually call notifyDataSetChanged() to have the changes
     * reflected in the attached view.
     *
     * The default is true, and calling notifyDataSetChanged()
     * resets the flag to true.
     *
     * @param notifyOnChange if true, modifications to the list will
     *                       automatically call {@link
     *                       #notifyDataSetChanged}
     */
    public void setNotifyOnChange(boolean notifyOnChange) {
        mNotifyOnChange = notifyOnChange;
    }

    private void init(Context context, int resource, int textViewResourceId, List<T> objects) {
        mContext = context;
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mResource = mDropDownResource = resource;
        mObjects = objects;
        mFieldId = textViewResourceId;
    }

    /**
     * Returns the context associated with this array adapter. The context is used
     * to create views from the resource passed to the constructor.
     *
     * @return The Context associated with this adapter.
     */
    public Context getContext() {
        return mContext;
    }

    /**
     * {@inheritDoc}
     */
    public int getCount() {
        return mObjects.size();
    }

    /**
     * {@inheritDoc}
     */
    public T getItem(int position) {
        return mObjects.get(position);
    }

    /**
     * Returns the position of the specified item in the array.
     *
     * @param item The item to retrieve the position of.
     *
     * @return The position of the specified item.
     */
    public int getPosition(T item) {
        return mObjects.indexOf(item);
    }

    /**
     * {@inheritDoc}
     */
    public long getItemId(int position) {
        return position;
    }

    /**
     * {@inheritDoc}
     */
    public View getView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(position, convertView, parent, mResource);
    }

    private View createViewFromResource(int position, View convertView, ViewGroup parent,
            int resource) {
        View view;
        TextView text;

        if (convertView == null) {
            view = mInflater.inflate(resource, parent, false);
        } else {
            view = convertView;
        }

        try {
            if (mFieldId == 0) {
                //  If no custom field is assigned, assume the whole resource is a TextView
                text = (TextView) view;
            } else {
                //  Otherwise, find the TextView field within the layout
                text = (TextView) view.findViewById(mFieldId);
            }
        } catch (ClassCastException e) {
            Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
            throw new IllegalStateException(
                    "ArrayAdapter requires the resource ID to be a TextView", e);
        }

        text.setText(getItem(position).toString());

        return view;
    }

    /**
     * <p>Sets the layout resource to create the drop down views.</p>
     *
     * @param resource the layout resource defining the drop down views
     * @see #getDropDownView(int, android.view.View, android.view.ViewGroup)
     */
    public void setDropDownViewResource(int resource) {
        this.mDropDownResource = resource;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(position, convertView, parent, mDropDownResource);
    }

    /**
     * Creates a new ArrayAdapter from external resources. The content of the array is
     * obtained through {@link android.content.res.Resources#getTextArray(int)}.
     *
     * @param context The application's environment.
     * @param textArrayResId The identifier of the array to use as the data source.
     * @param textViewResId The identifier of the layout used to create views.
     *
     * @return An ArrayAdapter<CharSequence>.
     */
    public static HRArrayAdapter<CharSequence> createFromResource(Context context,
            int textArrayResId, int textViewResId) {
        CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
        return new HRArrayAdapter<CharSequence>(context, textViewResId, strings);
    }

    /**
     * {@inheritDoc}
     */
    public HRArrayFilter getFilter() {
        if (mFilter == null) {
            mFilter = new HRArrayFilter();
        }
        return mFilter;
    }

    /**
     * <p>An array filter constrains the content of the array adapter with
     * a prefix. Each item that does not start with the supplied prefix
     * is removed from the list.</p>
     */
    private class HRArrayFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();

            if (mOriginalValues == null) {
                synchronized (mLock) {
                    mOriginalValues = new ArrayList<T>(mObjects);
                }
            }

            if (prefix == null || prefix.length() == 0) {
                synchronized (mLock) {
                    ArrayList<T> list = new ArrayList<T>(mOriginalValues);
                    results.values = list;
                    results.count = list.size();
                }
            } else {
                String prefixString = prefix.toString().toLowerCase();

                ArrayList<T> values = mOriginalValues;
                final int count = values.size();

                final ArrayList<T> newValues = new ArrayList<T>(count);
                final ArrayList<String> noPalatals = new ArrayList<String>();

                for (int i = 0; i < count; i++) {
                    final T value = values.get(i);
                    final String valueText = value.toString().toLowerCase();
                    String valueTextNoPalatals = toNoPalatals(valueText);
                    String prefixStringNoPalatals = toNoPalatals(prefixString);

                    //Log.d( "DATA NORMAL", valueText + ", " + prefixString );
                    //Log.d( "DATA NO PALATALS", valueTextNoPalatals + ", " + prefixStringNoPalatals );

                    // First match against the whole, non-splitted value
                    if (valueText.startsWith(prefixString) || valueTextNoPalatals.startsWith(prefixStringNoPalatals)) {
                        newValues.add(value);
                    } else {
                        final String[] words = valueText.split(" ");
                        final int wordCount = words.length;

                        for (int k = 0; k < wordCount; k++) {
                            if (words[k].startsWith(prefixString)) {
                                newValues.add(value);
                                break;
                            }
                        }
                    }
                }

                results.values = newValues;
                results.count = newValues.size();
            }

            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            //noinspection unchecked
            mObjects = (List<T>) results.values;
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }

        private String toNoPalatals( String original )
        {
            original = original.replace("Č", "C");
            original = original.replace("Ć", "C");
            original = original.replace("Š ", "S");
            original = original.replace("Đ", "D");
            original = original.replace("Ž", "Z");

            original = original.replace("č", "c");
            original = original.replace("ć", "c");
            original = original.replace("š", "s");
            original = original.replace("đ", "d");
            original = original.replace("ž", "z");

            return original;
        }
    }
}

Use this class as an ArrayAdapter (in this case it's for HR but it can be for any character).

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Changes for Croatian language done by Stevica Kuharski, IT4U
 * Web: http://www.it4u.com.hr/en
 * E-mail: [email protected] 
 */

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Comparator;
import java.util.Collections;

/**
 * A ListAdapter that manages a ListView backed by an array of arbitrary
 * objects.  By default this class expects that the provided resource id references
 * a single TextView.  If you want to use a more complex layout, use the constructors that
 * also takes a field id.  That field id should reference a TextView in the larger layout
 * resource.
 *
 * However the TextView is referenced, it will be filled with the toString() of each object in
 * the array. You can add lists or arrays of custom objects. Override the toString() method
 * of your objects to determine what text will be displayed for the item in the list.
 *
 * To use something other than TextViews for the array display, for instance, ImageViews,
 * or to have some of data besides toString() results fill the views,
 * override {@link #getView(int, View, ViewGroup)} to return the type of view you want.
 */
public class HRArrayAdapter<T> extends BaseAdapter implements Filterable {
    /**
     * Contains the list of objects that represent the data of this ArrayAdapter.
     * The content of this list is referred to as "the array" in the documentation.
     */
    private List<T> mObjects;

    /**
     * Lock used to modify the content of {@link #mObjects}. Any write operation
     * performed on the array should be synchronized on this lock. This lock is also
     * used by the filter (see {@link #getFilter()} to make a synchronized copy of
     * the original array of data.
     */
    private final Object mLock = new Object();

    /**
     * The resource indicating what views to inflate to display the content of this
     * array adapter.
     */
    private int mResource;

    /**
     * The resource indicating what views to inflate to display the content of this
     * array adapter in a drop down widget.
     */
    private int mDropDownResource;

    /**
     * If the inflated resource is not a TextView, {@link #mFieldId} is used to find
     * a TextView inside the inflated views hierarchy. This field must contain the
     * identifier that matches the one defined in the resource file.
     */
    private int mFieldId = 0;

    /**
     * Indicates whether or not {@link #notifyDataSetChanged()} must be called whenever
     * {@link #mObjects} is modified.
     */
    private boolean mNotifyOnChange = true;

    private Context mContext;    

    private ArrayList<T> mOriginalValues;
    private HRArrayFilter mFilter;

    private LayoutInflater mInflater;

    /**
     * Constructor
     *
     * @param context The current context.
     * @param textViewResourceId The resource ID for a layout file containing a TextView to use when
     *                 instantiating views.
     */
    public HRArrayAdapter(Context context, int textViewResourceId) {
        init(context, textViewResourceId, 0, new ArrayList<T>());
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a layout to use when
     *                 instantiating views.
     * @param textViewResourceId The id of the TextView within the layout resource to be populated
     */
    public HRArrayAdapter(Context context, int resource, int textViewResourceId) {
        init(context, resource, textViewResourceId, new ArrayList<T>());
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param textViewResourceId The resource ID for a layout file containing a TextView to use when
     *                 instantiating views.
     * @param objects The objects to represent in the ListView.
     */
    public HRArrayAdapter(Context context, int textViewResourceId, T[] objects) {
        init(context, textViewResourceId, 0, Arrays.asList(objects));
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a layout to use when
     *                 instantiating views.
     * @param textViewResourceId The id of the TextView within the layout resource to be populated
     * @param objects The objects to represent in the ListView.
     */
    public HRArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects) {
        init(context, resource, textViewResourceId, Arrays.asList(objects));
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param textViewResourceId The resource ID for a layout file containing a TextView to use when
     *                 instantiating views.
     * @param objects The objects to represent in the ListView.
     */
    public HRArrayAdapter(Context context, int textViewResourceId, List<T> objects) {
        init(context, textViewResourceId, 0, objects);
    }

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a layout to use when
     *                 instantiating views.
     * @param textViewResourceId The id of the TextView within the layout resource to be populated
     * @param objects The objects to represent in the ListView.
     */
    public HRArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects) {
        init(context, resource, textViewResourceId, objects);
    }

    /**
     * Adds the specified object at the end of the array.
     *
     * @param object The object to add at the end of the array.
     */
    public void add(T object) {
        if (mOriginalValues != null) {
            synchronized (mLock) {
                mOriginalValues.add(object);
                if (mNotifyOnChange) notifyDataSetChanged();
            }
        } else {
            mObjects.add(object);
            if (mNotifyOnChange) notifyDataSetChanged();
        }
    }

    /**
     * Inserts the specified object at the specified index in the array.
     *
     * @param object The object to insert into the array.
     * @param index The index at which the object must be inserted.
     */
    public void insert(T object, int index) {
        if (mOriginalValues != null) {
            synchronized (mLock) {
                mOriginalValues.add(index, object);
                if (mNotifyOnChange) notifyDataSetChanged();
            }
        } else {
            mObjects.add(index, object);
            if (mNotifyOnChange) notifyDataSetChanged();
        }
    }

    /**
     * Removes the specified object from the array.
     *
     * @param object The object to remove.
     */
    public void remove(T object) {
        if (mOriginalValues != null) {
            synchronized (mLock) {
                mOriginalValues.remove(object);
            }
        } else {
            mObjects.remove(object);
        }
        if (mNotifyOnChange) notifyDataSetChanged();
    }

    /**
     * Remove all elements from the list.
     */
    public void clear() {
        if (mOriginalValues != null) {
            synchronized (mLock) {
                mOriginalValues.clear();
            }
        } else {
            mObjects.clear();
        }
        if (mNotifyOnChange) notifyDataSetChanged();
    }

    /**
     * Sorts the content of this adapter using the specified comparator.
     *
     * @param comparator The comparator used to sort the objects contained
     *        in this adapter.
     */
    public void sort(Comparator<? super T> comparator) {
        Collections.sort(mObjects, comparator);
        if (mNotifyOnChange) notifyDataSetChanged();        
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
        mNotifyOnChange = true;
    }

    /**
     * Control whether methods that change the list ({@link #add},
     * {@link #insert}, {@link #remove}, {@link #clear}) automatically call
     * {@link #notifyDataSetChanged}.  If set to false, caller must
     * manually call notifyDataSetChanged() to have the changes
     * reflected in the attached view.
     *
     * The default is true, and calling notifyDataSetChanged()
     * resets the flag to true.
     *
     * @param notifyOnChange if true, modifications to the list will
     *                       automatically call {@link
     *                       #notifyDataSetChanged}
     */
    public void setNotifyOnChange(boolean notifyOnChange) {
        mNotifyOnChange = notifyOnChange;
    }

    private void init(Context context, int resource, int textViewResourceId, List<T> objects) {
        mContext = context;
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mResource = mDropDownResource = resource;
        mObjects = objects;
        mFieldId = textViewResourceId;
    }

    /**
     * Returns the context associated with this array adapter. The context is used
     * to create views from the resource passed to the constructor.
     *
     * @return The Context associated with this adapter.
     */
    public Context getContext() {
        return mContext;
    }

    /**
     * {@inheritDoc}
     */
    public int getCount() {
        return mObjects.size();
    }

    /**
     * {@inheritDoc}
     */
    public T getItem(int position) {
        return mObjects.get(position);
    }

    /**
     * Returns the position of the specified item in the array.
     *
     * @param item The item to retrieve the position of.
     *
     * @return The position of the specified item.
     */
    public int getPosition(T item) {
        return mObjects.indexOf(item);
    }

    /**
     * {@inheritDoc}
     */
    public long getItemId(int position) {
        return position;
    }

    /**
     * {@inheritDoc}
     */
    public View getView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(position, convertView, parent, mResource);
    }

    private View createViewFromResource(int position, View convertView, ViewGroup parent,
            int resource) {
        View view;
        TextView text;

        if (convertView == null) {
            view = mInflater.inflate(resource, parent, false);
        } else {
            view = convertView;
        }

        try {
            if (mFieldId == 0) {
                //  If no custom field is assigned, assume the whole resource is a TextView
                text = (TextView) view;
            } else {
                //  Otherwise, find the TextView field within the layout
                text = (TextView) view.findViewById(mFieldId);
            }
        } catch (ClassCastException e) {
            Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
            throw new IllegalStateException(
                    "ArrayAdapter requires the resource ID to be a TextView", e);
        }

        text.setText(getItem(position).toString());

        return view;
    }

    /**
     * <p>Sets the layout resource to create the drop down views.</p>
     *
     * @param resource the layout resource defining the drop down views
     * @see #getDropDownView(int, android.view.View, android.view.ViewGroup)
     */
    public void setDropDownViewResource(int resource) {
        this.mDropDownResource = resource;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(position, convertView, parent, mDropDownResource);
    }

    /**
     * Creates a new ArrayAdapter from external resources. The content of the array is
     * obtained through {@link android.content.res.Resources#getTextArray(int)}.
     *
     * @param context The application's environment.
     * @param textArrayResId The identifier of the array to use as the data source.
     * @param textViewResId The identifier of the layout used to create views.
     *
     * @return An ArrayAdapter<CharSequence>.
     */
    public static HRArrayAdapter<CharSequence> createFromResource(Context context,
            int textArrayResId, int textViewResId) {
        CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
        return new HRArrayAdapter<CharSequence>(context, textViewResId, strings);
    }

    /**
     * {@inheritDoc}
     */
    public HRArrayFilter getFilter() {
        if (mFilter == null) {
            mFilter = new HRArrayFilter();
        }
        return mFilter;
    }

    /**
     * <p>An array filter constrains the content of the array adapter with
     * a prefix. Each item that does not start with the supplied prefix
     * is removed from the list.</p>
     */
    private class HRArrayFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();

            if (mOriginalValues == null) {
                synchronized (mLock) {
                    mOriginalValues = new ArrayList<T>(mObjects);
                }
            }

            if (prefix == null || prefix.length() == 0) {
                synchronized (mLock) {
                    ArrayList<T> list = new ArrayList<T>(mOriginalValues);
                    results.values = list;
                    results.count = list.size();
                }
            } else {
                String prefixString = prefix.toString().toLowerCase();

                ArrayList<T> values = mOriginalValues;
                final int count = values.size();

                final ArrayList<T> newValues = new ArrayList<T>(count);
                final ArrayList<String> noPalatals = new ArrayList<String>();

                for (int i = 0; i < count; i++) {
                    final T value = values.get(i);
                    final String valueText = value.toString().toLowerCase();
                    String valueTextNoPalatals = toNoPalatals(valueText);
                    String prefixStringNoPalatals = toNoPalatals(prefixString);

                    //Log.d( "DATA NORMAL", valueText + ", " + prefixString );
                    //Log.d( "DATA NO PALATALS", valueTextNoPalatals + ", " + prefixStringNoPalatals );

                    // First match against the whole, non-splitted value
                    if (valueText.startsWith(prefixString) || valueTextNoPalatals.startsWith(prefixStringNoPalatals)) {
                        newValues.add(value);
                    } else {
                        final String[] words = valueText.split(" ");
                        final int wordCount = words.length;

                        for (int k = 0; k < wordCount; k++) {
                            if (words[k].startsWith(prefixString)) {
                                newValues.add(value);
                                break;
                            }
                        }
                    }
                }

                results.values = newValues;
                results.count = newValues.size();
            }

            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            //noinspection unchecked
            mObjects = (List<T>) results.values;
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }

        private String toNoPalatals( String original )
        {
            original = original.replace("Č", "C");
            original = original.replace("Ć", "C");
            original = original.replace("Š ", "S");
            original = original.replace("Đ", "D");
            original = original.replace("Ž", "Z");

            original = original.replace("č", "c");
            original = original.replace("ć", "c");
            original = original.replace("š", "s");
            original = original.replace("đ", "d");
            original = original.replace("ž", "z");

            return original;
        }
    }
}
韬韬不绝 2024-10-22 12:58:14

当您将字符串与用户输入进行比较时,您可能需要使用 Collat​​or...

http://download.oracle.com/javase/1.5.0/docs/api/java/text/Collat​​or.html

...调用 getInstance(),设置适当的强度,并使用比较或等于方法来查找与用户输入匹配的内容。

When you're comparing your strings to the users input, you might want to use a Collator...

http://download.oracle.com/javase/1.5.0/docs/api/java/text/Collator.html

...call getInstance(), set an appropriate strength, and use the compare or equals methods to find what matches the user input.

不疑不惑不回忆 2024-10-22 12:58:14

为了让人们的生活更轻松,您需要将以下内容添加到 @svenkapudija 的正确答案中,以实现法语口音字符兼容性。这是通过 Excel 在不到 40 秒内完成的

original = original.replace("À ", "A");
original = original.replace("à ", "a");
original = original.replace(" ", "A");
original = original.replace("â ", "a");
original = original.replace("Æ", "AE");
original = original.replace("æ", "ae");
original = original.replace("Ç", "C");
original = original.replace("ç", "c");
original = original.replace("È ", "E");
original = original.replace("è", "e");
original = original.replace("É ", "E");
original = original.replace("é", "e");
original = original.replace("Ê ", "E");
original = original.replace("ê ", "e");
original = original.replace("Ë ", "E");
original = original.replace("ë ", "e");
original = original.replace("Π", "I");
original = original.replace("î ", "i");
original = original.replace("Ï ", "I");
original = original.replace("ï ", "i");
original = original.replace("Ô", "O");
original = original.replace("ô", "o");
original = original.replace("Œ", "OE");
original = original.replace("œ", "oe");
original = original.replace("Ù", "U");
original = original.replace("ù", "u");
original = original.replace("Û", "U");
original = original.replace("û", "u");
original = original.replace("Ü", "U");
original = original.replace("ü", "u");

To make people's lives easier, here's what you need to add to the correct answer by @svenkapudija for French accented character compatibility. This was made via excel in less than 40 seconds

original = original.replace("À ", "A");
original = original.replace("à ", "a");
original = original.replace(" ", "A");
original = original.replace("â ", "a");
original = original.replace("Æ", "AE");
original = original.replace("æ", "ae");
original = original.replace("Ç", "C");
original = original.replace("ç", "c");
original = original.replace("È ", "E");
original = original.replace("è", "e");
original = original.replace("É ", "E");
original = original.replace("é", "e");
original = original.replace("Ê ", "E");
original = original.replace("ê ", "e");
original = original.replace("Ë ", "E");
original = original.replace("ë ", "e");
original = original.replace("Π", "I");
original = original.replace("î ", "i");
original = original.replace("Ï ", "I");
original = original.replace("ï ", "i");
original = original.replace("Ô", "O");
original = original.replace("ô", "o");
original = original.replace("Œ", "OE");
original = original.replace("œ", "oe");
original = original.replace("Ù", "U");
original = original.replace("ù", "u");
original = original.replace("Û", "U");
original = original.replace("û", "u");
original = original.replace("Ü", "U");
original = original.replace("ü", "u");
指尖上的星空 2024-10-22 12:58:14

对于来自波兰的人;):

        original = original.replace("Ą", "A");
        original = original.replace("Ć", "C");
        original = original.replace("Ę", "E");
        original = original.replace("Ł", "L");
        original = original.replace("Ń", "N");
        original = original.replace("Ó", "O");
        original = original.replace("Ś ", "S");
        original = original.replace("Ź", "Z");
        original = original.replace("Ż", "Z");

        original = original.replace("ą", "a");
        original = original.replace("ć", "c");
        original = original.replace("ę", "e");
        original = original.replace("ł", "l");
        original = original.replace("ń", "n");
        original = original.replace("ó", "o");
        original = original.replace("ś", "s");
        original = original.replace("ź", "z");
        original = original.replace("ż", "z");
        original = original.replace("ž", "z");

for people from poland ;):

        original = original.replace("Ą", "A");
        original = original.replace("Ć", "C");
        original = original.replace("Ę", "E");
        original = original.replace("Ł", "L");
        original = original.replace("Ń", "N");
        original = original.replace("Ó", "O");
        original = original.replace("Ś ", "S");
        original = original.replace("Ź", "Z");
        original = original.replace("Ż", "Z");

        original = original.replace("ą", "a");
        original = original.replace("ć", "c");
        original = original.replace("ę", "e");
        original = original.replace("ł", "l");
        original = original.replace("ń", "n");
        original = original.replace("ó", "o");
        original = original.replace("ś", "s");
        original = original.replace("ź", "z");
        original = original.replace("ż", "z");
        original = original.replace("ž", "z");
九命猫 2024-10-22 12:58:14

svenkapudija 的答案很好......我使用它并稍加修改只是为了确保变音符号过滤器适用于第一个单词之外的其他单词

                        final String[] words = valText.split(" ");
                        for (String word : words) {
                            if (word.startsWith(prefixString)||toNoPalatals(word).startsWith(prefixStringNoPalatals)) {
                                newValues.add(value);
                                break;
                            }
                        }
                    }

此外,这是针对来自捷克共和国的人;-)

    original = original.replace("Ě", "E");
    original = original.replace("Š", "S");
    original = original.replace("Č", "C");
    original = original.replace("Ř", "R");
    original = original.replace("Ž", "Z");
    original = original.replace("Ý", "Y");
    original = original.replace("Á", "A");
    original = original.replace("Í", "I");
    original = original.replace("É", "E");
    original = original.replace("Ú", "U");
    original = original.replace("Ů", "U");
    original = original.replace("Ď", "D");
    original = original.replace("Ť", "T");
    original = original.replace("Ň", "N");

    original = original.replace("ě", "e");
    original = original.replace("š", "s");
    original = original.replace("č", "c");
    original = original.replace("ř", "r");
    original = original.replace("ž", "z");
    original = original.replace("ý", "y");
    original = original.replace("á", "a");
    original = original.replace("í", "i");
    original = original.replace("é", "e");
    original = original.replace("ú", "u");
    original = original.replace("ů", "u");
    original = original.replace("ď", "d");
    original = original.replace("ť", "t");
    original = original.replace("ň", "n");

svenkapudija's answer is good...I used it and modified slightly just to ensure that the diacritics filter would work for other than first word

                        final String[] words = valText.split(" ");
                        for (String word : words) {
                            if (word.startsWith(prefixString)||toNoPalatals(word).startsWith(prefixStringNoPalatals)) {
                                newValues.add(value);
                                break;
                            }
                        }
                    }

Also, this is for people from Czech Republic ;-)

    original = original.replace("Ě", "E");
    original = original.replace("Š", "S");
    original = original.replace("Č", "C");
    original = original.replace("Ř", "R");
    original = original.replace("Ž", "Z");
    original = original.replace("Ý", "Y");
    original = original.replace("Á", "A");
    original = original.replace("Í", "I");
    original = original.replace("É", "E");
    original = original.replace("Ú", "U");
    original = original.replace("Ů", "U");
    original = original.replace("Ď", "D");
    original = original.replace("Ť", "T");
    original = original.replace("Ň", "N");

    original = original.replace("ě", "e");
    original = original.replace("š", "s");
    original = original.replace("č", "c");
    original = original.replace("ř", "r");
    original = original.replace("ž", "z");
    original = original.replace("ý", "y");
    original = original.replace("á", "a");
    original = original.replace("í", "i");
    original = original.replace("é", "e");
    original = original.replace("ú", "u");
    original = original.replace("ů", "u");
    original = original.replace("ď", "d");
    original = original.replace("ť", "t");
    original = original.replace("ň", "n");
贩梦商人 2024-10-22 12:58:14

@svenkapudija 的优秀答案可以使用 java.text.Normalizer 推广到大多数拉丁脚本语言。在过滤器代码中,将: 替换

                    String valueTextNoPalatals = toNoPalatals(valueText);
                    String prefixStringNoPalatals = toNoPalatals(prefixString);

为:

                String valueTextNoPalatals = Normalizer
                        .normalize(valueText, Normalizer.Form.NFD)
                        .replaceAll("[^\\p{ASCII}]", "")
                        .toLowerCase();

                String prefixStringNoPalatals = Normalizer
                        .normalize(prefixString, Normalizer.Form.NFD)
                        .replaceAll("[^\\p{ASCII}]", "")
                        .toLowerCase();

@svenkapudija 's excellent answer can be generalized to most Latin script languages using java.text.Normalizer. In the filter code, replace:

                    String valueTextNoPalatals = toNoPalatals(valueText);
                    String prefixStringNoPalatals = toNoPalatals(prefixString);

with:

                String valueTextNoPalatals = Normalizer
                        .normalize(valueText, Normalizer.Form.NFD)
                        .replaceAll("[^\\p{ASCII}]", "")
                        .toLowerCase();

                String prefixStringNoPalatals = Normalizer
                        .normalize(prefixString, Normalizer.Form.NFD)
                        .replaceAll("[^\\p{ASCII}]", "")
                        .toLowerCase();
ㄟ。诗瑗 2024-10-22 12:58:14

如果您需要推出自己的解决方案,则应考虑使用 accent-folding ,一种将 Unicode 重音字符串转换为 ASCII 文本的技术。您可以生成数组中所有字符串的 ASCII 版本,并将用户的部分查询与该数组进行匹配。

If you need to roll your own solution, you should consider using accent-folding, a technique for transforming Unicode accented strings into ASCII text. You could generate ASCII versions of all the strings in your array and match the user's partial query against that array, instead.

念﹏祤嫣 2024-10-22 12:58:14

对于斯洛伐克语:

    original = original.replace("Á", "A");
    original = original.replace("Ä", "A");
    original = original.replace("Č", "C");
    original = original.replace("Ď", "D");
    original = original.replace("É", "E");
    original = original.replace("Í", "I");
    original = original.replace("Ĺ", "L");
    original = original.replace("Ľ", "L");
    original = original.replace("Ň", "N");
    original = original.replace("Ó", "O");
    original = original.replace("Ô", "O");
    original = original.replace("Ŕ", "R");
    original = original.replace("Š", "S");
    original = original.replace("Ť", "T");
    original = original.replace("Ú", "U");
    original = original.replace("Ý", "Y");
    original = original.replace("Ž", "Z");

    original = original.replace("á", "a");
    original = original.replace("ä", "a");
    original = original.replace("č", "c");
    original = original.replace("ď", "d");
    original = original.replace("é", "e");
    original = original.replace("í", "i");
    original = original.replace("ĺ", "l");
    original = original.replace("ľ", "l");
    original = original.replace("ň", "n");
    original = original.replace("ó", "o");
    original = original.replace("ô", "o");
    original = original.replace("ŕ", "r");
    original = original.replace("š", "s");
    original = original.replace("ť", "t");
    original = original.replace("ú", "u");
    original = original.replace("ý", "y");
    original = original.replace("ž", "z");

For Slovak language:

    original = original.replace("Á", "A");
    original = original.replace("Ä", "A");
    original = original.replace("Č", "C");
    original = original.replace("Ď", "D");
    original = original.replace("É", "E");
    original = original.replace("Í", "I");
    original = original.replace("Ĺ", "L");
    original = original.replace("Ľ", "L");
    original = original.replace("Ň", "N");
    original = original.replace("Ó", "O");
    original = original.replace("Ô", "O");
    original = original.replace("Ŕ", "R");
    original = original.replace("Š", "S");
    original = original.replace("Ť", "T");
    original = original.replace("Ú", "U");
    original = original.replace("Ý", "Y");
    original = original.replace("Ž", "Z");

    original = original.replace("á", "a");
    original = original.replace("ä", "a");
    original = original.replace("č", "c");
    original = original.replace("ď", "d");
    original = original.replace("é", "e");
    original = original.replace("í", "i");
    original = original.replace("ĺ", "l");
    original = original.replace("ľ", "l");
    original = original.replace("ň", "n");
    original = original.replace("ó", "o");
    original = original.replace("ô", "o");
    original = original.replace("ŕ", "r");
    original = original.replace("š", "s");
    original = original.replace("ť", "t");
    original = original.replace("ú", "u");
    original = original.replace("ý", "y");
    original = original.replace("ž", "z");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文