代码之家  ›  专栏  ›  技术社区  ›  Alxandr

使用arrayadapter的android自定义过滤

  •  38
  • Alxandr  · 技术社区  · 15 年前

    我正在尝试筛选我的ListView,它填充了这个ArrayAdapter:

    package me.alxandr.android.mymir.adapters;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Set;
    
    import me.alxandr.android.mymir.R;
    import me.alxandr.android.mymir.model.Manga;
    import android.content.Context;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.Filter;
    import android.widget.SectionIndexer;
    import android.widget.TextView;
    
    public class MangaListAdapter extends ArrayAdapter<Manga> implements SectionIndexer
    {
        public ArrayList<Manga> items;
        public ArrayList<Manga> filtered;
        private Context context;
        private HashMap<String, Integer> alphaIndexer;
        private String[] sections = new String[0];
        private Filter filter;
        private boolean enableSections;
    
        public MangaListAdapter(Context context, int textViewResourceId, ArrayList<Manga> items, boolean enableSections)
        {
            super(context, textViewResourceId, items);
            this.filtered = items;
            this.items = filtered;
            this.context = context;
            this.filter = new MangaNameFilter();
            this.enableSections = enableSections;
    
            if(enableSections)
            {
                alphaIndexer = new HashMap<String, Integer>();
                for(int i = items.size() - 1; i >= 0; i--)
                {
                    Manga element = items.get(i);
                    String firstChar = element.getName().substring(0, 1).toUpperCase();
                    if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A')
                        firstChar = "@";
    
                    alphaIndexer.put(firstChar, i);
                }
    
                Set<String> keys = alphaIndexer.keySet();
                Iterator<String> it = keys.iterator();
                ArrayList<String> keyList = new ArrayList<String>();
                while(it.hasNext())
                    keyList.add(it.next());
    
                Collections.sort(keyList);
                sections = new String[keyList.size()];
                keyList.toArray(sections);
            }
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent)
        {
            View v = convertView;
            if(v == null)
            {
                LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.mangarow, null);
            }
    
            Manga o = items.get(position);
            if(o != null)
            {
                TextView tt = (TextView) v.findViewById(R.id.MangaRow_MangaName);
                TextView bt = (TextView) v.findViewById(R.id.MangaRow_MangaExtra);
                if(tt != null)
                    tt.setText(o.getName());
                if(bt != null)
                    bt.setText(o.getLastUpdated() + " - " + o.getLatestChapter());
    
                if(enableSections && getSectionForPosition(position) != getSectionForPosition(position + 1))
                {
                    TextView h = (TextView) v.findViewById(R.id.MangaRow_Header);
                    h.setText(sections[getSectionForPosition(position)]);
                    h.setVisibility(View.VISIBLE);
                }
                else
                {
                    TextView h = (TextView) v.findViewById(R.id.MangaRow_Header);
                    h.setVisibility(View.GONE);
                }
            }
    
            return v;
        }
    
        @Override
        public void notifyDataSetInvalidated()
        {
            if(enableSections)
            {
                for (int i = items.size() - 1; i >= 0; i--)
                {
                    Manga element = items.get(i);
                    String firstChar = element.getName().substring(0, 1).toUpperCase();
                    if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A')
                        firstChar = "@";
                    alphaIndexer.put(firstChar, i);
                }
    
                Set<String> keys = alphaIndexer.keySet();
                Iterator<String> it = keys.iterator();
                ArrayList<String> keyList = new ArrayList<String>();
                while (it.hasNext())
                {
                    keyList.add(it.next());
                }
    
                Collections.sort(keyList);
                sections = new String[keyList.size()];
                keyList.toArray(sections);
    
                super.notifyDataSetInvalidated();
            }
        }
    
        public int getPositionForSection(int section)
        {
            if(!enableSections) return 0;
            String letter = sections[section];
    
            return alphaIndexer.get(letter);
        }
    
        public int getSectionForPosition(int position)
        {
            if(!enableSections) return 0;
            int prevIndex = 0;
            for(int i = 0; i < sections.length; i++)
            {
                if(getPositionForSection(i) > position && prevIndex <= position)
                {
                    prevIndex = i;
                    break;
                }
                prevIndex = i;
            }
            return prevIndex;
        }
    
        public Object[] getSections()
        {
            return sections;
        }
    
        @Override
        public Filter getFilter()
        {
            if(filter == null)
                filter = new MangaNameFilter();
            return filter;
        }
    
        private class MangaNameFilter extends Filter
        {
    
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                // NOTE: this function is *always* called from a background thread, and
                // not the UI thread.
                constraint = constraint.toString().toLowerCase();
                FilterResults result = new FilterResults();
                if(constraint != null && constraint.toString().length() > 0)
                {
                    ArrayList<Manga> filt = new ArrayList<Manga>();
                    ArrayList<Manga> lItems = new ArrayList<Manga>();
                    synchronized (items)
                    {
                        Collections.copy(lItems, items);
                    }
                    for(int i = 0, l = lItems.size(); i < l; i++)
                    {
                        Manga m = lItems.get(i);
                        if(m.getName().toLowerCase().contains(constraint))
                            filt.add(m);
                    }
                    result.count = filt.size();
                    result.values = filt;
                }
                else
                {
                    synchronized(items)
                    {
                        result.values = items;
                        result.count = items.size();
                    }
                }
                return result;
            }
    
            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                // NOTE: this function is *always* called from the UI thread.
                filtered = (ArrayList<Manga>)results.values;
                notifyDataSetChanged();
            }
    
        }
    }
    

    但是,当我在过滤器上调用filter('test')时,什么也不会发生(或者后台线程正在运行,但是列表并没有被过滤到用户的消费范围内)。我该怎么解决?

    4 回复  |  直到 11 年前
        1
  •  43
  •   tim.paetz    13 年前

    这解决了我的问题。我不确定这是最好的解决方案,但它有效。我的项目是开源的,所以如果它被证明是有用的,请随意使用这里的任何代码:-)。

    package me.alxandr.android.mymir.adapters;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Set;
    
    import me.alxandr.android.mymir.R;
    import me.alxandr.android.mymir.model.Manga;
    import android.content.Context;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.Filter;
    import android.widget.SectionIndexer;
    import android.widget.TextView;
    
    public class MangaListAdapter extends ArrayAdapter<Manga> implements SectionIndexer
    {
        public ArrayList<Manga> items;
        public ArrayList<Manga> filtered;
        private Context context;
        private HashMap<String, Integer> alphaIndexer;
        private String[] sections = new String[0];
        private Filter filter;
        private boolean enableSections;
    
        public Manga getByPosition(int position)
        {
            return items.get(position);
        }
    
        public MangaListAdapter(Context context, int textViewResourceId, ArrayList<Manga> items, boolean enableSections)
        {
            super(context, textViewResourceId, items);
            this.filtered = items;
            this.items = ArrayList<Manga> items.clone();
            this.context = context;
            this.filter = new MangaNameFilter();
            this.enableSections = enableSections;
    
            if(enableSections)
            {
                alphaIndexer = new HashMap<String, Integer>();
                for(int i = items.size() - 1; i >= 0; i--)
                {
                    Manga element = items.get(i);
                    String firstChar = element.getName().substring(0, 1).toUpperCase();
                    if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A')
                        firstChar = "@";
    
                    alphaIndexer.put(firstChar, i);
                }
    
                Set<String> keys = alphaIndexer.keySet();
                Iterator<String> it = keys.iterator();
                ArrayList<String> keyList = new ArrayList<String>();
                while(it.hasNext())
                    keyList.add(it.next());
    
                Collections.sort(keyList);
                sections = new String[keyList.size()];
                keyList.toArray(sections);
            }
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent)
        {
            View v = convertView;
            if(v == null)
            {
                LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.mangarow, null);
            }
    
            Manga o = filtered.get(position);
            if(o != null)
            {
                TextView tt = (TextView) v.findViewById(R.id.MangaRow_MangaName);
                TextView bt = (TextView) v.findViewById(R.id.MangaRow_MangaExtra);
                if(tt != null)
                    tt.setText(o.getName());
                if(bt != null)
                    bt.setText(o.getLastUpdated() + " - " + o.getLatestChapter());
    
                if(enableSections && getSectionForPosition(position) != getSectionForPosition(position + 1))
                {
                    TextView h = (TextView) v.findViewById(R.id.MangaRow_Header);
                    h.setText(sections[getSectionForPosition(position)]);
                    h.setVisibility(View.VISIBLE);
                }
                else
                {
                    TextView h = (TextView) v.findViewById(R.id.MangaRow_Header);
                    h.setVisibility(View.GONE);
                }
            }
    
            return v;
        }
    
        @Override
        public void notifyDataSetInvalidated()
        {
            if(enableSections)
            {
                for (int i = items.size() - 1; i >= 0; i--)
                {
                    Manga element = items.get(i);
                    String firstChar = element.getName().substring(0, 1).toUpperCase();
                    if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A')
                        firstChar = "@";
                    alphaIndexer.put(firstChar, i);
                }
    
                Set<String> keys = alphaIndexer.keySet();
                Iterator<String> it = keys.iterator();
                ArrayList<String> keyList = new ArrayList<String>();
                while (it.hasNext())
                {
                    keyList.add(it.next());
                }
    
                Collections.sort(keyList);
                sections = new String[keyList.size()];
                keyList.toArray(sections);
    
                super.notifyDataSetInvalidated();
            }
        }
    
        public int getPositionForSection(int section)
        {
            if(!enableSections) return 0;
            String letter = sections[section];
    
            return alphaIndexer.get(letter);
        }
    
        public int getSectionForPosition(int position)
        {
            if(!enableSections) return 0;
            int prevIndex = 0;
            for(int i = 0; i < sections.length; i++)
            {
                if(getPositionForSection(i) > position && prevIndex <= position)
                {
                    prevIndex = i;
                    break;
                }
                prevIndex = i;
            }
            return prevIndex;
        }
    
        public Object[] getSections()
        {
            return sections;
        }
    
        @Override
        public Filter getFilter()
        {
            if(filter == null)
                filter = new MangaNameFilter();
            return filter;
        }
    
        private class MangaNameFilter extends Filter
        {
    
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                // NOTE: this function is *always* called from a background thread, and
                // not the UI thread.
                constraint = constraint.toString().toLowerCase();
                FilterResults result = new FilterResults();
                if(constraint != null && constraint.toString().length() > 0)
                {
                    ArrayList<Manga> filt = new ArrayList<Manga>();
                    ArrayList<Manga> lItems = new ArrayList<Manga>();
                    synchronized (this)
                    {
                        lItems.addAll(items);
                    }
                    for(int i = 0, l = lItems.size(); i < l; i++)
                    {
                        Manga m = lItems.get(i);
                        if(m.getName().toLowerCase().contains(constraint))
                            filt.add(m);
                    }
                    result.count = filt.size();
                    result.values = filt;
                }
                else
                {
                    synchronized(this)
                    {
                        result.values = items;
                        result.count = items.size();
                    }
                }
                return result;
            }
    
            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                // NOTE: this function is *always* called from the UI thread.
                filtered = (ArrayList<Manga>)results.values;
                notifyDataSetChanged();
                clear();
                for(int i = 0, l = filtered.size(); i < l; i++)
                    add(filtered.get(i));
                notifyDataSetInvalidated();
            }
    
        }
    }
    
        2
  •  32
  •   CoderDecoder user1229021    11 年前

    我觉得没有必要做以上任何事情。重写pojo like的toString()方法…

    public String toString() {
        return this.getCallTitle() == null ? "" :      
         this.getCallTitle().toLowerCase();
    }
    

    TextWatcher只是简单的过滤和一种更简单的方法。

    adapter.getFilter().filter(chars.toString().toLowerCase());
    

    除非您有非常自定义的筛选,否则此解决方案有效。 希望这对其他人有利。

        3
  •  12
  •   Alexander Pacha    12 年前

    我写的这门课基本上是 ArrayAdapter 只需稍加修改,类似于阿尔xandr溶液,但更优雅。

    我所做的就是从嵌套类中提取过滤器逻辑 ArrayAdapter.ArrayFilter 定制 -类来公开它(并允许用户重写它)。

    package com.example;
    
    /* 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. */
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    import android.content.Context;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.BaseAdapter;
    import android.widget.Filter;
    import android.widget.Filterable;
    import android.widget.TextView;
    
    /**
     * Slightly adopted ArrayAdapter. Basically a simple copy of ArrayAdapter with an extracted method filterObject() to
     * allow easy change of the filtering-behaviour.
     * 
     * A concrete BaseAdapter that is 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.
     * 
     * <p>
     * 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.
     * 
     * <p>
     * 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.
     * 
     * @param <T> The class, this adapter should hold
     */
    public class OGArrayAdapter<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;
    
        // A copy of the original mObjects array, initialized from and then used instead as soon as
        // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
        private ArrayList<T> mOriginalValues;
        private OGArrayFilter 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 OGArrayAdapter(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 OGArrayAdapter(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 OGArrayAdapter(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 OGArrayAdapter(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 OGArrayAdapter(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 OGArrayAdapter(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) {
            synchronized (mLock) {
                if (mOriginalValues != null) {
                    mOriginalValues.add(object);
                } else {
                    mObjects.add(object);
                }
            }
            if (mNotifyOnChange)
                notifyDataSetChanged();
        }
    
        /**
         * Adds the specified Collection at the end of the array.
         * 
         * @param collection The Collection to add at the end of the array.
         */
        public void addAll(Collection<? extends T> collection) {
            synchronized (mLock) {
                if (mOriginalValues != null) {
                    mOriginalValues.addAll(collection);
                } else {
                    mObjects.addAll(collection);
                }
            }
            if (mNotifyOnChange)
                notifyDataSetChanged();
        }
    
        /**
         * Adds the specified items at the end of the array.
         * 
         * @param items The items to add at the end of the array.
         */
        public void addAll(T... items) {
            synchronized (mLock) {
                if (mOriginalValues != null) {
                    Collections.addAll(mOriginalValues, items);
                } else {
                    Collections.addAll(mObjects, items);
                }
            }
            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) {
            synchronized (mLock) {
                if (mOriginalValues != null) {
                    mOriginalValues.add(index, object);
                } 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) {
            synchronized (mLock) {
                if (mOriginalValues != null) {
                    mOriginalValues.remove(object);
                } else {
                    mObjects.remove(object);
                }
            }
            if (mNotifyOnChange)
                notifyDataSetChanged();
        }
    
        /**
         * Remove all elements from the list.
         */
        public void clear() {
            synchronized (mLock) {
                if (mOriginalValues != null) {
                    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) {
            synchronized (mLock) {
                if (mOriginalValues != null) {
                    Collections.sort(mOriginalValues, comparator);
                } else {
                    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);
            }
    
            T item = getItem(position);
            if (item instanceof CharSequence) {
                text.setText((CharSequence) item);
            } else {
                text.setText(item.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 ArrayAdapter<CharSequence> createFromResource(Context context, int textArrayResId, int textViewResId) {
            CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
            return new ArrayAdapter<CharSequence>(context, textViewResId, strings);
        }
    
        /**
         * {@inheritDoc}
         */
        public Filter getFilter() {
            if (mFilter == null) {
                mFilter = new OGArrayFilter();
            }
            return mFilter;
        }
    
        /**
         * Performs filtering on the provided object and returns true, if the object should be in the filtered collection,
         * or false if it shouldn't.
         * 
         * @param myObject The object to be inspected
         * @param constraint Constraint, that the object has to fulfil
         * @return true, if the object should be in the filteredResult, false otherwise
         */
        protected boolean filterObject(T myObject, String constraint) {
            final String valueText = myObject.toString().toLowerCase();
    
            // First match against the whole, non-splitted value
            if (valueText.startsWith(constraint)) {
                return true;
            } else {
                final String[] words = valueText.split(" ");
                final int wordCount = words.length;
    
                // Start at index 0, in case valueText starts with space(s)
                for (int k = 0; k < wordCount; k++) {
                    if (words[k].startsWith(constraint)) {
                        return true;
                    }
                }
            }
    
            // No match, so don't add to collection
            return false;
        }
    
        /**
         * <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 OGArrayFilter 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) {
                    ArrayList<T> list;
                    synchronized (mLock) {
                        list = new ArrayList<T>(mOriginalValues);
                    }
                    results.values = list;
                    results.count = list.size();
                } else {
                    String prefixString = prefix.toString().toLowerCase();
    
                    ArrayList<T> values;
                    synchronized (mLock) {
                        values = new ArrayList<T>(mOriginalValues);
                    }
    
                    final int count = values.size();
                    final ArrayList<T> newValues = new ArrayList<T>();
    
                    for (int i = 0; i < count; i++) {
                        final T value = values.get(i);
                        if (filterObject(value, prefixString)) {
                            newValues.add(value);
                        }
                    }
    
                    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();
                }
            }
        }
    }
    

    此解决方案的好处是它在应用程序中很漂亮,只需将从arrayadapter.arrayfilter类中提取的filteroobject方法重写到arrayadapter中即可:

    public class MyAdapter extends OGArrayAdapter<OGScene> {
        // Do the rest of your adapter
    
        @Override
        protected boolean filterObject(OGScene myObject, String constraint) {
            // If true, the object will be in the list, if false, it will be filtered.
            // Do your own filtering with myObject as you desire
            return myObject.fulfillsConstraint(constraint);
        }
    }
    
        4
  •  6
  •   Ben    11 年前

    我发现过滤arrayadapter的最佳方法是创建自己的过滤类:

    private class MyFilter extends Filter
    

    然后在该函数中创建新的对象数组以在筛选后显示(您可以在 class ArrayAdapter )

    @Override
    protected FilterResults performFiltering(CharSequence prefix)
    

    现在诀窍就在这个方法里

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results)
    

    使用阵列适配器时 不能 这样做:

    myAdapterData = results.values
    

    从那时起,断开数据与超级数据的连接,必须这样做才能保留对超级原始数据数组的引用:

    data.clear();
    data.addAll((List<YourType>) results.values);
    

    然后重写

    GETFILTER()

    在适配器中,例如:

    @Override
    public Filter getFilter() {
        if (filter == null) {
            filter = new MyFilter();
        }
        return filter;
    }