前言:
最近做到這個功能,在這裡做個紀錄。以前我使用SearchBar的功能是我給後台值,後台直接給我收尋結果。
但如果使用到的收尋結果必須要前端(App端)實作呢?
這裡就教你如何前端做收尋應用。
重點程式碼:
重點都是圍繞在Filter。可以看一下官方文檔, 讓我們把畫面帶到Protected methods
在待會我們實作RecyclerView的時候繼承 Filterable 會用到getFilter() 方法,好讓我們在activity調用adapter時使用篩選。
還會再Adapter內實作一個自己的Filter,這時候會override複寫下方兩種方法。
performFiltering 執行篩選
publishResults 篩選結果
SearchView的部分,必須implements SearchView.OnQueryTextListener。
Public methods | |
|---|---|
abstract boolean | onQueryTextChange(String newText)
Called when the query text is changed by the user.
|
abstract boolean | onQueryTextSubmit(String query)
Called when the user submits the query.
|
onQueryTextChange 當使用者改變searchview的字體時,call此方法。
onQueryTextSubmit 當使用者按下送出時,call此方法。
實作:
這裡提供 SearchView + ListView 的實作方法。[AndroidStudio] 使用 SearchView 過濾列表資料 —
http://disp.cc/b/11-9ded
裡面的內容清楚明瞭。
如果有問題可以在這裡問。
我實作了一個demo:https://drive.google.com/open?id=0Byk75IYx-dKXWTUya0hKaWtXX3M
但ListView近期已經被RecyclerView代替了。
在RecyclerView內的adapter並沒有filter的方法,因此我們要在Adapter內實作。
提供一個SearchView + RecyclerView的方法
作者:Lipt0n
連結:http://www.jianshu.com/p/5078c7fec29e
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
此處就是在Adapter內實作Filterable並使用的很好範例。
等等我做的東西是實踐在這個上面的東西,就不提供DEMO了。
所有的收尋都拿String當例子,簡單明瞭!
但如果我要客製化呢?變成一個item的搜尋模式該怎麼辦呢?
這邊包含可以搜尋文字。
如果每個item的文字都不一樣,是可以分開收尋的。
只要你的文字內有關鍵字,都會跑在下面的結果內。
如圖:
完整程式碼:
先來看看 今日我們會動到的地方:因為會有網路下載圖片的功能,所以先在manifest加入Gilde。
如何加入這篇有提到
http://nikeru8.blogspot.tw/2017/03/third-party-frescopicasso.html
就不再贅述。
然後你還要一張default image,供給如果Gilde還沒下載完成時的預設圖片。
http://lmgtfy.com/?q=default_image
這邊必須強調一下預設圖片和文字的重要性,如果RecyclerView讀取不到你的圖片或是文字,因為他內在的回收機制,他會去偷取其他item的圖片作為預設圖片。你也知道後果了。文不對題,或是錯位的問題就會絡繹不絕。
![]() |
| activity_main.xml |
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context="com.hello.kaiser.searchbar.MainActivity">
<android.support.v7.widget.SearchView
android:id="@+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
先看activity的佈局文件。
先把xml畫好畫滿。
item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/image_view"
android:layout_width="100dp"
android:layout_height="100dp"
android:padding="5dp" />
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:textSize="30dp" />
</LinearLayout>
再來先把工具寫出來,我們要塞物件的DATA
DATA.java
public class Data {
private String title;
private String imageUrl;
// public Data(String title, String imageUrl) {
// this.title = title;
// this.imageUrl = imageUrl;
// Log.d("ItemData", "CheckPoint imageUrl=" + imageUrl);
// }
public String getTitle() {
return title;
}
public String getImageUrl() {
return imageUrl;
}
public void setTitle(String title) {
this.title = title;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
這裡我們要塞圖片和文字。
把我們MainActivity.java 全部補上吧。
public class MainActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {
//元件
private android.support.v7.widget.SearchView searchView;
private RecyclerView recyclerView;
private ArrayList<Data> datalists = new ArrayList<>();
private String[] urlList = null;
private String[] titleList = null;
private DataAdapter dataAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initSet();
}
/**
* 這方法在activity所有畫面都完成之後,才會被call。
* 之前我做的專案,有很多Crash案例都是因為畫面還沒完成,點擊事件就先放行,點擊後導致Crash。
*/
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
initListener();
}
/**
* init畫面
*/
private void initView() {
searchView = (android.support.v7.widget.SearchView) findViewById(R.id.search_bar);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
}
/**
* init設定
*/
private void initSet() {
//RecyclerView設定
dataAdapter = new DataAdapter(this);
LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(llm);
searchView.setOnQueryTextListener(this);
searchView.setIconifiedByDefault(false); //是否要點選搜尋圖示後再打開輸入框
searchView.setFocusable(false);
searchView.requestFocusFromTouch(); //要點選後才會開啟鍵盤輸入
searchView.setSubmitButtonEnabled(false);//輸入框後是否要加上送出的按鈕
searchView.setQueryHint("請輸入android搜尋"); //輸入框沒有值時要顯示的提示文字
//假資料設定
urlList = new String[]{
"http://www.jrtstudio.com/sites/default/files/ico_android.png",
"https://developer.android.com/_static/images/android/touchicon-180.png",
"http://cdn.bgr.com/2012/11/android-icon.jpg?quality=98&strip=all",
"http://www.fastbooting.com/uploads/5/5/9/9/55994511/1474140_orig.png",
"http://www.pendidikan-diy.go.id/dinas_v4/img/up_down/Android.png",
"https://www.android.com/static/2016/img/one/a1_andy_1x.png",
"http://zdnet2.cbsistatic.com/hub/i/2016/04/22/a1ced73f-6628-4930-96f4-d224e1d3a707/8a43709ccee674396403ee99472e38f3/android-security-1.jpg",
"https://unwire.pro/wp-content/uploads/2017/05/android-kotlin.png",
"http://www.jrtstudio.com/sites/default/files/ico_android.png",
"https://developer.android.com/_static/images/android/touchicon-180.png",
"http://cdn.bgr.com/2012/11/android-icon.jpg?quality=98&strip=all",
"http://www.fastbooting.com/uploads/5/5/9/9/55994511/1474140_orig.png",
"http://www.pendidikan-diy.go.id/dinas_v4/img/up_down/Android.png",
"https://www.android.com/static/2016/img/one/a1_andy_1x.png",
"http://zdnet2.cbsistatic.com/hub/i/2016/04/22/a1ced73f-6628-4930-96f4-d224e1d3a707/8a43709ccee674396403ee99472e38f3/android-security-1.jpg",
"https://unwire.pro/wp-content/uploads/2017/05/android-kotlin.png",
};
titleList = new String[]{
"手機:iphone7",
"手機殼:犀牛盾",
"手機:htc",
"電腦:戴爾",
"手機:samsung",
"電腦:hp惠普",
"電腦:惠普",
"電腦:蘋果電腦apple",
"手機:sony",
"手機:samsung s8",
"手機:asus",
"電腦:Auser宏碁電腦",
"手機、電腦:微軟",
"手機:oppo 蕩漾款",
"手機:小米",
"電腦:聯想",
};
//兩筆假資料size()一樣才進入迴圈
if (titleList.length == urlList.length)
for (int i = 0; i < (urlList.length); i++) {
Data data = new Data();//製作單筆資料
data.setTitle(titleList[i]);
data.setImageUrl(urlList[i]);
datalists.add(data);//把單筆資料加入陣列
}
dataAdapter.setData(datalists);//把陣列塞入adapter
recyclerView.setAdapter(dataAdapter);//把adapter塞入recyclerview
}
/**
* 點擊事件
*/
private void initListener() {
}
/**
* 複寫implements SearchView.OnQueryTextListener 的方法
*/
@Override
public boolean onQueryTextSubmit(final String query) {
return false;
}
@Override
public boolean onQueryTextChange(final String newText) {
//塞選 我們寫在adapter內
dataAdapter.getFilter().filter(newText);
return false;
}
}
重頭戲Adapter
DataAdapter.java
class DataAdapter extends RecyclerView.Adapter<DataAdapter.dataHolder> implements Filterable {
private final static String TAG = DataAdapter.class.getSimpleName();
//元件
private Context context;
private ArrayList<data> datalists;//是會變動的陣列,用來顯示正個recyclerView的資料
private ArrayList<data> filterDatas;//固定陣列,用來和filter比對用的。
private MyFliter myFliter;//讓mainActivity能使用adapter呼叫篩選功能
//建構子
public DataAdapter(Context context) {
this.context = context;
}
//implements Filterable的必定覆寫的方法,讓我們在activity內能呼叫他
@Override
public Filter getFilter() {
if (myFliter == null) {
myFliter = new MyFliter();
}
return myFliter;
}
class dataHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
private TextView textView;
public dataHolder(View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.image_view);
textView = (TextView) itemView.findViewById(R.id.text_view);
}
}
//讓我們在activity內能讀取或更新adapter內data的資料
public void setData(ArrayList<data> datalists) {
this.datalists = datalists;
filterDatas = datalists;
notifyDataSetChanged();
}
@Override
public DataAdapter.dataHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
dataHolder dh = new dataHolder(view);
return dh;
}
@Override
public void onBindViewHolder(DataAdapter.dataHolder holder, int position) {
Glide.with(context)
.load(datalists.get(position).getImageUrl())
.placeholder(R.drawable.default_image)
.into(holder.imageView);
if (!TextUtils.isEmpty(datalists.get(position).getTitle()))
holder.textView.setText(datalists.get(position).getTitle());
else
holder.textView.setText("暫無資料");
}
@Override
public int getItemCount() {
return datalists == null ? 0 : datalists.size();
}
//實作自己的篩選Filter
class MyFliter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence filterContent) {
ArrayList<data> filterData = new ArrayList<>();
//先判斷filterContent是不是null才進入
if (filterContent != null && filterContent.toString().trim().length() > 0) {
Log.d(TAG, "確認是否為空值。 filterData.size = " + filterData.size());
//這回圈是在判斷你輸入的文字(filterContent)是否有在filterDatas陣列內有相關的文字,逐條搜尋。
for (int i = 0; i < filterDatas.size(); i++) {
String content = filterDatas.get(i).getTitle();
Log.d(TAG, "確認是否進入for迴圈 content = " + content);
if (content.contains(String.valueOf(filterContent))) {
Log.d(TAG, "確認輸入文字是否相同。");
Data data = new Data();
data.setImageUrl(filterDatas.get(i).getImageUrl());
data.setTitle(filterDatas.get(i).getTitle());
filterData.add(data);
}
}
} else {
filterData = filterDatas;
Log.d(TAG, "確認什麼都沒打 filterDatas = datalists = " + filterData.size());
}
FilterResults filterResults = new FilterResults();
filterResults.count = filterData.size();
filterResults.values = filterData;
Log.d(TAG, "final size = " + filterResults.count);
return filterResults;
}
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
datalists = (ArrayList<data>) filterResults.values;
if (filterResults.count > 0) {
notifyDataSetChanged();
} else {
Data data = new Data();
data.setTitle("沒有結果");
datalists.add(data);
notifyDataSetChanged();
}
}
}
}
MyFliter 這方法內強破複寫兩種方法
performFiltering 執行篩選
publishResults 篩選結果
在performFiltering內
1、我先判斷在SearchView內的有無輸入任何文字(是否為null)
2、在寫一個for迴圈,把所有進入adatper陣列資料內的title String做比對,如果有相同的文字,就創建一個data物件,塞入你要篩選存放的ArrayList內。
3、 比對完之後把你篩選存放的ArrayList丟入FilterResults內。
在publishFiltering內
1、datalists是在adapter內會變動的陣列,用來顯示RecyclerView用的(filterDatas為固定陣列,用來和filter做資料比對)
2、 把剛剛在performFiltering抓取到的filterResults匯到datalists內。用以顯示recyclerView
3、假如陣列大於0,就notifyDataSetChanged刷新RecyclerView。
在performFiltering內
1、我先判斷在SearchView內的有無輸入任何文字(是否為null)
2、在寫一個for迴圈,把所有進入adatper陣列資料內的title String做比對,如果有相同的文字,就創建一個data物件,塞入你要篩選存放的ArrayList內。
3、 比對完之後把你篩選存放的ArrayList丟入FilterResults內。
在publishFiltering內
1、datalists是在adapter內會變動的陣列,用來顯示RecyclerView用的(filterDatas為固定陣列,用來和filter做資料比對)
2、 把剛剛在performFiltering抓取到的filterResults匯到datalists內。用以顯示recyclerView
3、假如陣列大於0,就notifyDataSetChanged刷新RecyclerView。
DEMO: https://drive.google.com/open?id=0Byk75IYx-dKXNXEzdzlzUEwzc3M



沒有留言:
張貼留言