package com.shunzhi.parent.adapter; import android.content.Context; import android.content.res.Resources; import android.support.annotation.IdRes; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; 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.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * Created by Administrator on 2016/7/4. */ public class MyArrayAdapter extends BaseAdapter implements Filterable, MyThemedSpinnerAdapter { private final Object mLock = new Object(); private final LayoutInflater mInflater; private List mObjects; private int mResource; private int mDropDownResource; private int mFieldId = 0; private boolean mNotifyOnChange = true; private Context mContext; private ArrayList mOriginalValues; private ArrayFilter mFilter; private LayoutInflater mDropDownInflater; public MyArrayAdapter(Context context, @LayoutRes int resource) { this(context, resource, 0, new ArrayList()); } public MyArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId) { this(context, resource, textViewResourceId, new ArrayList()); } public MyArrayAdapter(Context context, @LayoutRes int resource, @NonNull List objects) { this(context, resource, 0, objects); } /** * Constructor * * @param context The current context. * @param resource 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 MyArrayAdapter(Context context, @LayoutRes int resource, @NonNull T[] objects) { this(context, resource, 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 MyArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId, @NonNull T[] objects) { this(context, resource, textViewResourceId, Arrays.asList(objects)); } public MyArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId, @NonNull List objects) { mContext = context; mInflater = LayoutInflater.from(context); mResource = mDropDownResource = resource; mObjects = objects; mFieldId = textViewResourceId; } 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 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 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; } /** * 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(mInflater, position, convertView, parent, mResource); } private View createViewFromResource(LayoutInflater inflater, int position, View convertView, ViewGroup parent, int resource) { View view; TextView text; if (convertView == null) { view = inflater.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) { 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; } /** *

Sets the layout resource to create the drop down views.

* * @param resource the layout resource defining the drop down views * @see #getDropDownView(int, View, ViewGroup) */ public void setDropDownViewResource(@LayoutRes int resource) { this.mDropDownResource = resource; } /** * Sets the {@link Resources.Theme} against which drop-down views are * inflated. *

* By default, drop-down views are inflated against the theme of the * {@link Context} passed to the adapter's constructor. * * @param theme the theme against which to inflate drop-down views or * {@code null} to use the theme from the adapter's context * @see #getDropDownView(int, View, ViewGroup) */ @Override public void setDropDownViewTheme(Resources.Theme theme) { if (theme == null) { mDropDownInflater = null; } else if (theme == mInflater.getContext().getTheme()) { mDropDownInflater = mInflater; } // else { // final Context context = new ContextThemeWrapper(mContext, theme); // mDropDownInflater = LayoutInflater.from(context); // } } @Override public Resources.Theme getDropDownViewTheme() { return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme(); } @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater; return createViewFromResource(inflater, position, convertView, parent, mDropDownResource); } public Filter getFilter() { if (mFilter == null) { mFilter = new ArrayFilter(); } return mFilter; } private class ArrayFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList(mObjects); } } if (prefix == null || prefix.length() == 0) { ArrayList list; synchronized (mLock) { list = new ArrayList(mOriginalValues); } results.values = list; results.count = list.size(); } else { String prefixString = prefix.toString().toLowerCase(); ArrayList values; synchronized (mLock) { values = new ArrayList(mOriginalValues); } final int count = values.size(); final ArrayList newValues = new ArrayList(); for (int i = 0; i < count; i++) { final T value = values.get(i); final String valueText = value.toString().toLowerCase(); // First match against the whole, non-splitted value if (valueText.startsWith(prefixString)) { newValues.add(value); } 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].contains(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) results.values; if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } }