今天的主題是RecyclerView + searchView的實作

用白話文講就是常看到的搜尋啦XD

 

unnamed

 

當然,或許機制有點不一樣,不過整體來說就是一樣的東西不用懷疑(;´д`)ゞ

 

那麼今天做出來會是怎樣呢?直接看範例最快!

 

Github在此

->https://github.com/thumbb13555/RecyclerViewWithSearch/tree/master

 


 

1. 結構

 

其實今天的這個主題也是一個RecyclerView的應用之一

蛤?不知道RecyclerView?

看這篇吧XD

->碼農日常-『Android studio』基本RecyclerView用法

 

不過今天的重點是在寫搜尋的方法以及設置SearchView的方法

 

先來看一下專案結構吧

截圖 2020-11-07 下午2.36.33

 


 

2. 拉介面&設置SearchView

 

menu.xml

截圖 2020-11-07 下午2.49.39

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_search"
        android:title="Search"
        android:icon="@drawable/ic_baseline_search_24"
        app:showAsAction="always|collapseActionView"
        app:actionViewClass="androidx.appcompat.widget.SearchView"
        />
</menu>

基本上按照上方的做法就完成設置界面了

ViewClass的部分一定要指定,不然會無法取得他的控制項(有點接近設置繼承(´∀`)

再來是主介面樣式(就是個RecyclerVIew....)

 

activity_main.xml

截圖 2020-11-07 下午2.53.34

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

 


 

3. 設置RecyclerView的Adapter

 

先PO全部

 

RecyclerViewAdapter.java

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements Filterable {

    /**上方的arrayList為RecyclerView所綁定的ArrayList*/
    ArrayList<String> arrayList;
    /**儲存最原先ArrayList的狀態(也就是充當回複RecyclerView最原先狀態的陣列)*/
    ArrayList<String> arrayListFilter;

    public RecyclerViewAdapter(ArrayList<String> arrayList) {
        this.arrayList = arrayList;
        arrayListFilter = new ArrayList<>();
        /**這裡把初始陣列複製進去了*/
        arrayListFilter.addAll(arrayList);

    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
        TextView tvItem;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            tvItem = itemView.findViewById(android.R.id.text1);
            /**點擊事件*/
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            Toast.makeText(itemView.getContext(), arrayList.get(getAdapterPosition())
                    , Toast.LENGTH_SHORT).show();
        }
    }


    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(android.R.layout.simple_list_item_1,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.tvItem.setText(arrayList.get(position));
    }

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

    @Override
    public Filter getFilter() {
        return mFilter;
    }
    /**使用Filter濾除方法*/
    Filter mFilter = new Filter() {
        /**此處為正在濾除字串時所做的事*/
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            /**先將完整陣列複製過去*/
            ArrayList<String> filteredList = new ArrayList<>();
            /**如果沒有輸入,則將原本的陣列帶入*/
            if (constraint == null || constraint.length() == 0) {
                filteredList.addAll(arrayListFilter);
            } else {
                /**如果有輸入,則照順序濾除相關字串
                 * 如果你有更好的搜尋演算法,就是寫在這邊*/
                for (String movie: arrayListFilter) {
                    if (movie.toLowerCase().contains(constraint.toString().toLowerCase())) {
                        filteredList.add(movie);
                    }
                }
            }
            /**回傳濾除結果*/
            FilterResults filterResults = new FilterResults();
            filterResults.values = filteredList;
            return filterResults;
        }
        /**將濾除結果推給原先RecyclerView綁定的陣列,並通知RecyclerView刷新*/
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            arrayList.clear();
            arrayList.addAll((Collection<? extends  String>) results.values);
            notifyDataSetChanged();
        }
    };
}

 

 

Okay,這部分有兩個重點

1. 設置RecyclerView本身

2. 設置Filter

 

接下來我按照我的順序來講述這裡的寫法

首先是設置RecyclerView本身

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>{

    /**上方的arrayList為RecyclerView所綁定的ArrayList*/
    ArrayList<String> arrayList;
    /**儲存最原先ArrayList的狀態(也就是充當回複RecyclerView最原先狀態的陣列)*/
    ArrayList<String> arrayListFilter;

    public RecyclerViewAdapter(ArrayList<String> arrayList) {
        this.arrayList = arrayList;
        arrayListFilter = new ArrayList<>();
        /**這裡把初始陣列複製進去了*/
        arrayListFilter.addAll(arrayList);

    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
        TextView tvItem;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            tvItem = itemView.findViewById(android.R.id.text1);
            /**點擊事件*/
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            Toast.makeText(itemView.getContext(), arrayList.get(getAdapterPosition())
                    , Toast.LENGTH_SHORT).show();
        }
    }


    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(android.R.layout.simple_list_item_1,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.tvItem.setText(arrayList.get(position));
    }

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

}

 

 

RecyclerView的Adapter其實就是輸入一個陣列後一直去改這個陣列的一個過程

所以在初始化時我們就宣布了兩個陣列

/**上方的arrayList為RecyclerView所綁定的ArrayList*/
ArrayList<String> arrayList;
/**儲存最原先ArrayList的狀態(也就是充當回複RecyclerView最原先狀態的陣列)*/
ArrayList<String> arrayListFilter;

public RecyclerViewAdapter(ArrayList<String> arrayList) {
    this.arrayList = arrayList;
    arrayListFilter = new ArrayList<>();
    /**這裡把初始陣列複製進去了*/
    arrayListFilter.addAll(arrayList);

}

 

如註解所說,arrayList的那個陣列就是綁定給RecyclerView元件的陣列

也因此想要使RecyclerView有變化,便是要修改arrayList的陣列

 

那arrayListFilter這個部分就是用來存最初始的那個陣列用的

...Emmm也就是最原先的狀態

 

再來是第二個部分Filter

 

直接PO~

 

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements Filterable {

    //(略)
     .
     .

    @Override
    public int getItemCount() {
        return arrayList.size();
    }
    //(以下新增)
    @Override
    public Filter getFilter() {
        return mFilter;
    }
    /**使用Filter濾除方法*/
    Filter mFilter = new Filter() {
        /**此處為正在濾除字串時所做的事*/
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            /**先將完整陣列複製過去*/
            ArrayList<String> filteredList = new ArrayList<>();
            /**如果沒有輸入,則將原本的陣列帶入*/
            if (constraint == null || constraint.length() == 0) {
                filteredList.addAll(arrayListFilter);
            } else {
                /**如果有輸入,則照順序濾除相關字串
                 * 如果你有更好的搜尋演算法,就是寫在這邊*/
                for (String movie: arrayListFilter) {
                    if (movie.toLowerCase().contains(constraint.toString().toLowerCase())) {
                        filteredList.add(movie);
                    }
                }
            }
            /**回傳濾除結果*/
            FilterResults filterResults = new FilterResults();
            filterResults.values = filteredList;
            return filterResults;
        }
        /**將濾除結果推給原先RecyclerView綁定的陣列,並通知RecyclerView刷新*/
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            arrayList.clear();
            arrayList.addAll((Collection<? extends  String>) results.values);
            notifyDataSetChanged();
        }
    };
}

 

 


 

4. 設置主要控制(MainActivity)

 

一樣,先全部

 

MainActivity.java

public class MainActivity extends AppCompatActivity {

    RecyclerViewAdapter mAdapter;
    String[] strings = {"CRUISER MK. I","CRUISER MK. II","VALENTINE","CRUISER MK. III"
            ,"CRUISER MK. IV","COVENANTER","CRUSADER","GSR 3301 SETTER","LHMTV","GSOR3301 AVR FS"
            ,"MANTICORE","MATILDA","CHURCHILL I","CHURCHILL VII","BLACK PRINCE","CAERNARVON"
            ,"CONQUEROR","SUPER CONQUEROR","CAVALIER","CROMWELL","COMET","CENTURION MK. I"
            ,"CENTURION MK. 7/1","CENTURION ACTION X","VALENTINE AT","BISHOP","FV304"
            ,"CRUSADER 5.5-IN. SP","FV207","FV3805","CONQUEROR GUN CARRIAGE"
            ,"AT 2","ACHILLES","CHALLENGER","CHARIOTEER","FV4004 CONWAY","FV4005 STAGE II"
            ,"AT 8","AT 7","AT 15","TORTOISE","FV217 BADGER"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        ArrayList arrayList = new ArrayList();
        for (int i = 0; i < strings.length; i++) {
            arrayList.add(strings[i]);
        }
        mAdapter = new RecyclerViewAdapter(arrayList);
        recyclerView.setAdapter(mAdapter);

    }

    /**初始化Toolbar內SearchView的設置*/
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        getMenuInflater().inflate(R.menu.menu, menu);
        MenuItem menuItem = menu.findItem(R.id.action_search);
        SearchView searchView = (SearchView) menuItem.getActionView();
        /**SearchView設置,以及輸入內容後的行動*/
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                /**調用RecyclerView內的Filter方法*/
                mAdapter.getFilter().filter(newText);
                return false;
            }
        });
        return super.onCreateOptionsMenu(menu);
    }
}

 

 

半部onCreate內就是設置RecyclerView元件本身的設置

半部為設置SearchView的部分

 

再來searchView在輸入時,其觸發點就是onQueryTextChange的這個部分

而這個部分就是調用RecyclerViewAdapter.java內Filter本身的方法

也就是在RecyclerViewAdapter.java中這個部分

 

@Override
public Filter getFilter() {
    return mFilter;
}
/**使用Filter濾除方法*/
Filter mFilter = new Filter() {
    /**此處為正在濾除字串時所做的事*/
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        /**先將完整陣列複製過去*/
        ArrayList<String> filteredList = new ArrayList<>();
        /**如果沒有輸入,則將原本的陣列帶入*/
        if (constraint == null || constraint.length() == 0) {
            filteredList.addAll(arrayListFilter);
        } else {
            /**如果有輸入,則照順序濾除相關字串
             * 如果你有更好的搜尋演算法,就是寫在這邊*/
            for (String movie: arrayListFilter) {
                if (movie.toLowerCase().contains(constraint.toString().toLowerCase())) {
                    filteredList.add(movie);
                }
            }
        }
        /**回傳濾除結果*/
        FilterResults filterResults = new FilterResults();
        filterResults.values = filteredList;
        return filterResults;
    }
    /**將濾除結果推給原先RecyclerView綁定的陣列,並通知RecyclerView刷新*/
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        arrayList.clear();
        arrayList.addAll((Collection<? extends  String>) results.values);
        notifyDataSetChanged();
    }
};

 

到這邊都寫上後,本次的功能應該是完成囉 :D

你做出來了嗎XD

 

那今天的文章到這邊囉!

謝謝各位

TK

arrow
arrow
    創作者介紹
    創作者 碼農日常 的頭像
    碼農日常

    碼農日常大小事

    碼農日常 發表在 痞客邦 留言(6) 人氣()