【问题标题】:Custom getFilter in custom ArrayAdapter in androidandroid中自定义ArrayAdapter中的自定义getFilter
【发布时间】:2013-10-08 00:08:53
【问题描述】:

我在自定义 arrayAdapter 中实现自定义 getFilter 时遇到问题。其实我不知道如何实现它。尝试了各种代码,但仍然没有运气。这是我的自定义数组适配器。

package com.test.FilterableList.Adapters;

import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.test.FilterableList.Models.ListTO;
import com.test.FilterableList.R;

import android.widget.Filterable;


public class FilterableAdapter extends ArrayAdapter<ListTO> implements Filterable {

    // declaring our ArrayList of items
    public ArrayList<ListTO> objects;

    /* here we must override the constructor for ArrayAdapter
    * the only variable we care about now is ArrayList<Item> objects,
    * because it is the list of objects we want to display.
    */
    public FilterableAdapter(Context context, int textViewResourceId, ArrayList<ListTO> objects) {
        super(context, textViewResourceId, objects);
        this.objects = objects;
    }

    /*
     * we are overriding the getView method here - this is what defines how each
     * list item will look.
     */
    public View getView(int position, View convertView, ViewGroup parent){

        // assign the view we are converting to a local variable
        View v = convertView;

        // first check to see if the view is null. if so, we have to inflate it.
        // to inflate it basically means to render, or show, the view.
        if (v == null) {
            LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(R.layout.list_item, null);
        }

        /*
         * Recall that the variable position is sent in as an argument to this method.
         * The variable simply refers to the position of the current object in the list. (The ArrayAdapter
         * iterates through the list we sent it)
         *
         * Therefore, i refers to the current Item object.
         */
        ListTO i = objects.get(position);

        if (i != null) {

            // This is how you obtain a reference to the TextViews.
            // These TextViews are created in the XML files we defined.

            TextView tt = (TextView) v.findViewById(R.id.list_name);
            if (tt != null){
                tt.setText(i.FileName);
            }



        }

        // the view must be returned to our activity
        return v;

    }
}

这是 ListTO 类。

package com.test.FilterableList.Models;

public class ListTO {

    public int Id;
    public String FileName;
    public String FileUri;

    public ListTO(int id, String fileName, String fileUri) {

        Id = id;
        FileName = fileName;
        FileUri = fileUri;

    }

}

这是布局。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@drawable/blacklikenbackground"
    tools:context=".AllListActivity" >

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Search"
        android:id="@+id/inputSearch"
        />


    <ListView
        android:id="@+id/test_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </ListView>

</LinearLayout>

这里的搜索关键字来自“inputSearch”EditText。

这是文本更改的侦听器。

 inputSearch.addTextChangedListener(new TextWatcher() {

                    @Override
                    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
                        // When user changed the Text
                      //  Toast.makeText(getActivity(), cs.toString(), Toast.LENGTH_LONG).show();
                        m_adapter.getFilter().filter(cs);
                    }

                    @Override
                    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
                                                  int arg3) {
                        // TODO Auto-generated method stub

                    }

                    @Override
                    public void afterTextChanged(Editable arg0) {
                        // TODO Auto-generated method stub
                    }
                });

谢谢。

【问题讨论】:

  • 您到底想达到什么目标?过滤器数据将来自哪里,您希望过滤器做什么?
  • 我还建议您看看这个出色的答案:stackoverflow.com/a/14369336/72746 - 这可能就是您要找的。​​span>
  • @Axarydax 抱歉,布局已添加到问题中。实际上 Search 关键字来自“inputSearch”EditText。我想实现谷歌中使用的自动建议功能;但是从列表视图来看。
  • ArrayAdapter 抽象了所有这些功能,您只需要覆盖 ListTO 上的 toString()。查看它的实现grepcode.com/file/repository.grepcode.com/java/ext/…@chandu tangudu 答案是正确的

标签: android android-listview android-arrayadapter


【解决方案1】:

您遇到了问题,主要是因为您使用的是自定义对象。如果您将 String 或 int 值传递给数组适配器,它知道如何过滤它。但是,如果您通过自定义对象默认过滤器实现,则不知道如何处理。

虽然尚不清楚您要在过滤器中执行什么操作,但我建议您按照以下步骤操作。

  1. 正确实现ListTO,尽管它与您现在的目标无关
  2. 实现自定义过滤器
  3. 归还您的过滤器

实现自定义过滤器

您要做的第一件事是,来自阵列适配器的implements Filterable

其次,提供你的Filter的实现

Filter myFilter = new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
         FilterResults filterResults = new FilterResults();   
         ArrayList<ListTO> tempList=new ArrayList<ListTO>();
         //constraint is the result from text you want to filter against. 
         //objects is your data set you will filter from
         if(constraint != null && objects!=null) {
             int length=objects.size();
             int i=0;
                while(i<length){
                    ListTO item=objects.get(i);
                    //do whatever you wanna do here
                    //adding result set output array     

                    tempList.add(item);

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

      @SuppressWarnings("unchecked")
      @Override
      protected void publishResults(CharSequence contraint, FilterResults results) {
          objects = (ArrayList<ListTO>) results.values;
          if (results.count > 0) {
           notifyDataSetChanged();
          } else {
              notifyDataSetInvalidated();
          }  
      }
     };

最后一步,

@Override
     public Filter getFilter() {
        return myFilter;
    }

【讨论】:

  • 您能帮我解决我的问题吗:stackoverflow.com/questions/20524417/…。我遵循了该方法,但 ListView 就消失了。
  • @minhaz 我已经实现了您的解决方案并且效果很好,但是我遇到了一个问题,如果我搜索一个字符串然后将空格返回到空,它不会显示所有数组项.
  • 我也面临同样的问题,当我退格时没有任何效果。
  • @minhaz 我不明白的一件事是您在publishResults 中重新分配objects,因此您丢失了原始列表??
  • 这样做:- if (searchquery.length()
【解决方案2】:

无需编写数组适配器。编写一个 toString() 方法,它应该返回文件名的值。

喜欢

public class ListTO {

    public int Id;
    public String FileName;
    public String FileUri;

    public ListTO(int id, String fileName, String fileUri) {

        Id = id;
        FileName = fileName;
        FileUri = fileUri;

    }

    public String toString(){
        return FileName
    }

}

【讨论】:

  • 如果您只需要基本搜索,这是一个很棒且简单的解决方案。 +1
  • 这不仅仅是伟大的,这是不重新发明轮子的正确答案
  • 非常适合实现简单搜索
【解决方案3】:

您需要覆盖 Adapter 中的 getFilter() 方法并提供您自己的过滤器。 看看这个Filterable Example 看看实际的实现。

将以下getFilter() 代码添加到您的FilterableAdapter 类中,并用您的过滤器填充它:

/* (non-Javadoc)
 * @see android.widget.ArrayAdapter#getFilter()
 */
@Override
public Filter getFilter() {
    return new Filter() {

        /* (non-Javadoc)
         * @see android.widget.Filter#performFiltering(java.lang.CharSequence)
         */
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            // TODO Auto-generated method stub
            /*
             * Here, you take the constraint and let it run against the array
             * You return the result in the object of FilterResults in a form
             * you can read later in publichResults.
             */
            return null;
        }

        /* (non-Javadoc)
         * @see android.widget.Filter#publishResults(java.lang.CharSequence, android.widget.Filter.FilterResults)
         */
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            // TODO Auto-generated method stub
            /*
             * Here, you take the result, put it into Adapters array
             * and inform about the the change in data.
             */
        }

    };
}

我在 cmets 中添加了提示。

【讨论】:

    【解决方案4】:

    试试这个:

         public class Adptr extends BaseAdapter implements Filterable {
    public ArrayList<Model> modelValues;
    
    private Activity activity;
    private LayoutInflater layoutinflater;
    private List<Model> mOriginalValues;
    private int PositionSelected = 0;
    
    public Adptr (ArrayList<Model> modelValues, Activity activity) {
        super();
        this.modelValues = modelValues;
        this.activity = activity;
    
    
    }
    
    @Override
    public int getCount() {
    
        return modelValues.size();
    }
    
    @Override
    public Object getItem(int position) {
    
        return modelValues.get(position);
    }
    
    @Override
    public long getItemId(int position) {
    
        return position;
    }
    
    
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
    
        layoutinflater = (LayoutInflater)  activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        ViewHolder holder = null;
        Model model = modelValues.get(position);
    
        if (convertView == null || !(convertView.getTag() instanceof ViewHolder)) {
            convertView = layoutinflater.inflate(R.layout.row_search, null);
            holder = new ViewHolder();
            holder.txtName = (TextView) convertView.findViewById(R.id.row_serch_txt_name);
    
    
    
    
            convertView.setTag(holder);
            convertView.setTag(R.id.row_serch_txt_name, holder.txtName);
    
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
    
        holder.txtArtistName.setText("" + modelValue.get_NAME());
    
    
    
    
        return convertView;
    }
    
    class ViewHolder {
        TextView txtName;
    
    
    }
    
    @Override
    public Filter getFilter() {
    
        Filter filter = new Filter() {
    
            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
    
                modelValues = (ArrayList<ModelValueArtist>) results.values; // has
    
                notifyDataSetChanged();
            }
    
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults(); // Holds the
                                                                // results of a
                                                                // filtering
                                                                // operation in
                                                                // values
                // List<String> FilteredArrList = new ArrayList<String>();
                List<Model> FilteredArrList = new ArrayList<Model>();
    
                if (mOriginalValues == null) {
                    mOriginalValues = new ArrayList<Model>(modelValues); // saves
    
                }
    
                /********
                 * 
                 * If constraint(CharSequence that is received) is null returns
                 * the mOriginalValues(Original) values else does the Filtering
                 * and returns FilteredArrList(Filtered)
                 * 
                 ********/
                if (constraint == null || constraint.length() == 0) {
    
                    // set the Original result to return
                    results.count = mOriginalValues.size();
                    results.values = mOriginalValues;
                } else {
                    Locale locale = Locale.getDefault();
                    constraint = constraint.toString().toLowerCase(locale);
                    for (int i = 0; i < mOriginalValues.size(); i++) {
                        Model model = mOriginalValues.get(i);
    
                        String data = model.get_NAME();
                        if (data.toLowerCase(locale).contains(constraint.toString())) {
    
                            FilteredArrList.add(modelMyMall);
                        }
                    }
                    // set the Filtered result to return
                    results.count = FilteredArrList.size();
                    results.values = FilteredArrList;
    
                }
                return results;
            }
        };
        return filter;
      }
    
         }
    

    【讨论】:

    • 我一个字一个字地用这个词,但没有用。建议覆盖ArrayAdapter 中的getCount(),它只是过滤结果数量而不是结果本身。我在publishResults() 中结束了mThis.clear();mThis.addAll(customList);
    【解决方案5】:

    您可以在自定义对象类中覆盖 toString() 并返回要过滤掉的 String 对象。

    @Override
    public void toString(){
          return this.toBeFilteredString;
    }
    

    然后简单地使用arrayAdapter的默认内置过滤器并使用它调用它

    adapter.getFilter().filter(Charsequence c);
    

    【讨论】:

    • 正是我想要的! :)
    • 那里也一样!在编写了公认的解决方案后,我寻找了像这样更简单的东西......谢谢!
    【解决方案6】:

    我在 SO 上搜索了很多答案以获得所需的所有 sn-ps。所以这是我的班级Registration 的自定义过滤器的 Kotlin 版本。 这个确实有效,您需要的所有信息都在此代码中。

    class RegistrationArrayAdapter(context: Context, private val layoutResId: Int, registrations: List<Registration>) :
        ArrayAdapter<Registration>(context, layoutResId, registrations) {
    
        private val filter = RegistrationFilter(registrations)
    
        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
            val registration = getItem(position)
            val view = convertView ?: LayoutInflater.from(context).inflate(layoutResId, null)
            (view as TextView).text = registration?.mainGuest?.name ?: ""
            return view
        }
    
        override fun getFilter() = filter
    
        inner class RegistrationFilter(private val originalList: List<Registration>) : Filter() {
    
            private val sourceObjects: ArrayList<Registration> = ArrayList()
    
            init {
                synchronized (this) {
                    sourceObjects.addAll(originalList)
                }
            }
    
            override fun performFiltering(constraint: CharSequence?): FilterResults {
                if (constraint == null) return FilterResults()
    
                val result = FilterResults()
    
                if (constraint.isNotEmpty()) {
                    val filteredList = ArrayList<Registration>()
    
                    sourceObjects.filterTo(filteredList) { isWithinConstraint(it, constraint) }
    
                    result.count = filteredList.size
                    result.values = filteredList
    
                } else {
                    synchronized(this) {
                        result.values = sourceObjects
                        result.count = sourceObjects.size
                    }
    
                }
                return result
            }
    
            override fun publishResults(constraint: CharSequence?, results: FilterResults) {
                if (results.values == null) return
    
                @Suppress("UNCHECKED_CAST")
                val filtered = results.values as ArrayList<Registration>
    
                if (results.count > 0) {
                    clear()
                    addAll(filtered)
                    notifyDataSetChanged()
                } else {
                    notifyDataSetInvalidated()
                }
    
            }
    
    
            override fun convertResultToString(resultValue: Any?): CharSequence {
                return (resultValue as Registration).mainGuest.name
            }
    
            private fun isWithinConstraint(registration: Registration, constraint: CharSequence): Boolean {
                return registration.mainGuest.name.toLowerCase().contains(constraint, true)
            }
    
        }
    }
    

    【讨论】:

    • 你是唯一的救星!!没有其他解决方案可以像您那样工作。
    【解决方案7】:

    正如你所说“我想实现类似谷歌中使用的自动建议功能;但这里是从列表视图中。-重做”

    还有另一种方法可以使用 自动完成文本视图

    更多详情请通过AutoCompleteTextView

    OutPut 将如下所示

    ma​​in.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/listitem_layout"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#e2e2e2"
        android:orientation="vertical" >
    
        <AutoCompleteTextView
                android:id="@+id/autocomplete"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_margin="10dp"
                android:background="@drawable/text_area"
                android:inputType="text|textNoSuggestions|textMultiLine"
                android:paddingLeft="10dp"
                android:popupBackground="#EFEEEC"
                android:textColor="#333333"
                android:textColorHint="#9c9c9c"
                android:textSize="18sp"
                android:completionThreshold="1" />
    
    </LinearLayout>
    

    auto_textview.xml

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="12dp"
        android:textColor="#333333"
        android:layout_margin="15dp"
        android:textSize="16sp" >
    </TextView>
    

    MainActivity.java

    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            AutoCompleteTextView seachView = (AutoCompleteTextView) findViewById(R.id.autocomplete);
            seachView.setAdapter(new ArrayAdapter<String>(this,
                    R.layout.auto_textview, getHeading()));
        }
    
        /**
         * @return
         */
        public List<String> getHeading() {
            List<String> list = new ArrayList<String>();
            list.add("Android");
            list.add("Arnold");
            list.add("Blackberry");
            list.add("Blackpearl");
            list.add("Country");
            list.add("Canada");
            list.add("City");
            list.add("Street Address");
            list.add("Objective C");
            return list;
        }
    
    }
    

    希望这会对你有所帮助。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多