1. 程式人生 > >SearchView+Filter對資料進行簡單過濾

SearchView+Filter對資料進行簡單過濾

轉:https://www.jianshu.com/p/5078c7fec29e

我是使用ListView實現展示系統應用的demo

執行邏輯是這樣的:

  1. 通過SearchView獲取使用者輸入的文字.
  2. 把文字傳到Adpater,在Adpater中對關鍵字進行篩選.
  3. 根據過濾後的結果重新整理RecyclerView顯示過濾後的介面.

先看佈局檔案:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_action"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.project.granden.enjoy.MyAction.ActionActivity">


    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?actionBarSize"
        android:background="#bc4a4a">


        <android.support.v7.widget.SearchView
            android:id="@+id/search_view"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="right">

        </android.support.v7.widget.SearchView>
    </android.support.v7.widget.Toolbar>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/toolbar">

    </android.support.v7.widget.RecyclerView>

</RelativeLayout>

一個Toolbar置於頂部裡面包含一個SearchView,剩餘的顯示RecyclerView

然後看程式碼部分:

public class ActionActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {



    SearchView searchView;
    Toolbar toolbar;
    RecyclerView recyclerView;
    MyAdpater adpter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_action);
        InitVIew();
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        List<String>list=new ArrayList<>();
        for (int i = 0; i < 15; i++) {
            list.add(String.valueOf(i));
        }
        adpter=new MyAdpater(list);
        recyclerView.setAdapter(adpter);
}



    private void InitVIew() {
        recyclerView= (RecyclerView) findViewById(R.id.recyclerview);
        toolbar= (Toolbar) findViewById(R.id.toolbar);
        searchView= (SearchView) findViewById(R.id.search_view);
        searchView.setOnQueryTextListener(this);

    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
       
             adpter.getFilter().filter(newText);
 
      return false;
    }
}

主要看Activity實現的介面:SearchView.OnQueryTextListener

實現該介面後覆寫兩個方法它們的作用就是對SearchView的輸入框進行監聽:

  1. onQueryTextSubmit 當完成輸入的內容點選搜尋按鈕後該方法會回撥,引數String query返回當前文字框可見的文字
  2. onQueryTextChange 每次當文字框的內容發生改變該方法會回撥,引數String newText返回當前文字框可見的文字

可以看到我們在onQueryTextChange()方法中呼叫了adpter.getFilter().filter(newText);
他的作用就是對Adpater的內容進行過濾.

每當SearchView的輸入框內容發生變化就把輸入框的內容傳送到Adpater的過濾器接著進行一系列的操作.

public class MyAdpater extends RecyclerView.Adapter<MyAdpater.ViewHolder> implements Filterable {
    List number,temp_number;
    TestFilter myFilter;

    public MyAdpater(List<String> number) {

        this.number=number;
        temp_number = number;
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.test, null);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.number.setText((String) number.get(position));
    }

    @Override
    public int getItemCount() {
        return number.size();
    }

    @Override
    public Filter getFilter() {

        if (myFilter == null) {
            myFilter = new TestFilter();
        }
        return myFilter;
    }


    class ViewHolder extends RecyclerView.ViewHolder {
        TextView number;

        public ViewHolder(View itemView) {
            super(itemView);
            number = (TextView) itemView.findViewById(R.id.number);
        }
    }

    class TestFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {

            List<String> new_number=new ArrayList();
            if (constraint != null && constraint.toString().trim().length() > 0) {
                for (int i = 0; i < temp_number.size(); i++) {
                    String content = (String) temp_number.get(i);
                    if (content.contains(constraint)) {
                        new_number.add(content);
                    }
                }

            }else {
                new_number=temp_number;
            }
            FilterResults filterResults = new FilterResults();
            filterResults.count = new_number.size();
            filterResults.values = new_number;
            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            //這裡對number進行過濾後重新賦值
            number = (List) results.values;
            //如果過濾後的返回的值的個數大於等於0的話,對Adpater的介面進行重新整理
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                 //否則說明沒有任何過濾的結果,直接提示使用者"沒有符合條件的結果"
                umber = new ArrayList(){};
                number.add(": ( 沒有符合條件的結果");
                notifyDataSetChanged();
            }

        }
    }
}

來看看Adpater的內部:

  1. MyAdpater(List number)構造方法接收一個List引數
  2. 並且把number賦值給了temp_number(原因後面會解釋)
  3. 細心的同學可能早就看到了我們實現了Filterable介面,這個方法需要覆寫getFilter()方法.
public Filter getFilter() {

        if (myFilter == null) {
            myFilter = new TestFilter();
        }
        return myFilter;
    }

方法需要返回Filter,所以我們新建一個TestFilter類繼承至Filter

class TestFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {

            List<String> new_number=new ArrayList();
            if (constraint != null && constraint.toString().trim().length() > 0) {
                for (int i = 0; i < temp_number.size(); i++) {
                    String content = (String) temp_number.get(i);
                    if (content.contains(constraint)) {
                        new_number.add(content);
                    }
                }

            }else {
                new_number=temp_number;
            }
            FilterResults filterResults = new FilterResults();
            filterResults.count = new_number.size();
            filterResults.values = new_number;
            return filterResults;
        }

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

            number = (List) results.values;
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                number.add(": ( 沒有符合條件的結果");
                notifyDataSetChanged();
            }

        }
}

Filter類裡面有兩個方法:

performFiltering:引數constraint是adpter.getFilter().filter(newText)方法傳入的newText(也就是過濾的條件)
該方法主要完成對資料進行過濾的工作

publishResults:引數CharSequence,results第一個引數這裡不需要用到,第二個引數是上面的performFiltering返回的值.

在該方法裡面進行介面的重新整理工作

裡面實現的思路是:

  1. 新建一個List new_number這個物件用來儲存過濾後符合條件的值
  2. 判斷constraint是否為空,是否有值.滿足條件的話遍歷List,並且判斷List的值是否有包含過濾的條件.如果是的話把值存到new_number.如果一個符合的都沒有把temp_number的值(也就是最開始傳進來的List)賦值給new_number
  3. 新建一個FilterResults物件分別把new_number的size和value賦值給FilterResults.value和FilterResults.count,然後返回FilterResults物件
  4. 接著在publishResults()方法中取出過濾後滿足條件的值也就是results.values
  5. 判斷results.count的過濾後結果的個數是否大於0
  6. 大於0的話把值賦值給number然後重新整理介面,不滿足的話把temp_number(也就是最開始傳進來的值)賦值給number,然後重新整理介面

以上就是Adpater中Filter過濾器的使用和解釋