看板 KnucklesNote
作者 標題 [AndroidStudio] 使用 SearchView 過濾列表資料
時間 2016-01-26 Tue. 17:46:04
新增一個搜尋看板頁,輸入每個字母時就會顯示可能的看板名稱
![[圖]](http://i.imgur.com/mNYUowa.png)
加上搜尋輸入框 SearchView
在頁面佈局xml檔,加上 SearchView 與 ListView
<SearchView android:id="@+id/searchview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ListView android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#555"
android:dividerHeight="1px"/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ListView android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#555"
android:dividerHeight="1px"/>
在頁面的類別程式檔
加上這幾個成員變數
ListView mListView;
ArrayAdapter mSearchAdapter;
ArrayList<String> mSearchList = new ArrayList<>();
boolean mIsSearch = false;
mSearchList 用來儲存所有看板名稱的字串陣列ArrayAdapter mSearchAdapter;
ArrayList<String> mSearchList = new ArrayList<>();
boolean mIsSearch = false;
mIsSearch 用來記錄 ListView 是否已載入 Adapter
新增一個成員函式 loadData()
private void loadData(){
String urlString = "http://disp.cc/api/get.php?act=bSearchList";
AsyncHttpClient client = new AsyncHttpClient();
client.get(urlString, new JsonHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
JSONArray list = response.optJSONArray("list");
JSONObject board;
for(int i=0; i<list.length(); i++){
board = list.optJSONObject(i);
mSearchList.add(board.optString("name") + " " + board.optString("title"));
}
}
@Override
public void onFailure(int statusCode, Header[] headers, Throwable e, JSONObject error) {
Toast.makeText(getApplicationContext(),
"Error: " + statusCode + " " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
});
}
使用 Asynchronous Http Client 下載所有看板的資料String urlString = "http://disp.cc/api/get.php?act=bSearchList";
AsyncHttpClient client = new AsyncHttpClient();
client.get(urlString, new JsonHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
JSONArray list = response.optJSONArray("list");
JSONObject board;
for(int i=0; i<list.length(); i++){
board = list.optJSONObject(i);
mSearchList.add(board.optString("name") + " " + board.optString("title"));
}
}
@Override
public void onFailure(int statusCode, Header[] headers, Throwable e, JSONObject error) {
Toast.makeText(getApplicationContext(),
"Error: " + statusCode + " " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
});
}
並轉為字串陣列存在 mSearchList
在成員函式 onCreate() 加上
SearchView searchView = (SearchView) findViewById(R.id.searchview);
searchView.setOnQueryTextListener(this);
searchView.setIconifiedByDefault(false); //是否要點選搜尋圖示後再打開輸入框
searchView.setFocusable(false);
searchView.requestFocusFromTouch(); //要點選後才會開啟鍵盤輸入
searchView.setSubmitButtonEnabled(false);//輸入框後是否要加上送出的按鈕
searchView.setQueryHint("輸入看板名稱"); //輸入框沒有值時要顯示的提示文字
mListView = (ListView) findViewById(R.id.listview);
mSearchAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mSearchList);
loadData();
searchView.setOnQueryTextListener(this);
searchView.setIconifiedByDefault(false); //是否要點選搜尋圖示後再打開輸入框
searchView.setFocusable(false);
searchView.requestFocusFromTouch(); //要點選後才會開啟鍵盤輸入
searchView.setSubmitButtonEnabled(false);//輸入框後是否要加上送出的按鈕
searchView.setQueryHint("輸入看板名稱"); //輸入框沒有值時要顯示的提示文字
mListView = (ListView) findViewById(R.id.listview);
mSearchAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mSearchList);
loadData();
依編輯器的提示,在類別的 implements 加上 SearchView.OnQueryTextListener
並加上成員函式 onQueryTextChange() 與 onQueryTextSubmit()
當搜尋框內的文字改變時,會執行 onQueryTextChange()
輸入完按下確定時,會執行 onQueryTextSubmit()
因為資料是使用陣列,所以可以用 ArrayAdapter 將資料轉為 Adapter
不用自己再寫一個繼承 BaseAdapter 的類別
建立 ArrayAdapter 時使用的 android.R.layout.simple_list_item_1
為內建的 xml 資源,用這個就不用自己建 xml 檔
ListView 先不要載入 Adapter,等搜尋框有輸入文字時再載入
修改兩個新增的成員函式為
@Override
public boolean onQueryTextChange(String newText) {
if(!mIsSearch && newText.length()!=0) { //搜尋框有值時
mListView.setAdapter(mSearchAdapter);
mIsSearch = true;
}else if(mIsSearch && newText.length()==0){ //搜尋框是空的時
mListView.setAdapter(null);
mIsSearch = false;
}
if(mIsSearch) { //過濾Adapter的內容
Filter filter = mSearchAdapter.getFilter();
filter.filter(newText);
}
return true;
}
@Override
public boolean onQueryTextSubmit(String query) {
Toast.makeText(this, "輸入的是:" + query, Toast.LENGTH_SHORT).show();
return true;
}
public boolean onQueryTextChange(String newText) {
if(!mIsSearch && newText.length()!=0) { //搜尋框有值時
mListView.setAdapter(mSearchAdapter);
mIsSearch = true;
}else if(mIsSearch && newText.length()==0){ //搜尋框是空的時
mListView.setAdapter(null);
mIsSearch = false;
}
if(mIsSearch) { //過濾Adapter的內容
Filter filter = mSearchAdapter.getFilter();
filter.filter(newText);
}
return true;
}
@Override
public boolean onQueryTextSubmit(String query) {
Toast.makeText(this, "輸入的是:" + query, Toast.LENGTH_SHORT).show();
return true;
}
在搜尋框輸入文字時,先用 mIsSearch 確認是否已載入Adapter
若還未載入,且有輸入文字時,才載入 Adapter
若已載入 Adapter,但輸入文字被刪除時,使用
mListView.setAdapter(null); 來移除 Adapter
當搜尋框有輸入文字時,使用 ArrayAdapter 提供的 getFilter 來過濾 Adapter 的內容
設定列表的點擊事件
在 onCreate() 加上
mListView.setOnItemClickListener(this);
依編輯器提示加上 implements AdapterView.OnItemClickListener
以及成員函式 onItemClick()
修改成員函式 onItemClick() 為
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//從ArrayAdapter中用getItem取出第position項的資料
String itemString = (String) parent.getAdapter().getItem(position);
Pattern pattern = Pattern.compile("^(\\S+) (.*)$");
Matcher matcher = pattern.matcher(itemString);
String boardName="", boardTitle="";
if(matcher.find()){
boardName = matcher.group(1);
boardTitle = matcher.group(2);
}
Intent intent = new Intent(this, TextListActivity.class);
intent.putExtra("boardName", boardName);
intent.putExtra("boardTitle", boardTitle);
startActivity(intent);
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//從ArrayAdapter中用getItem取出第position項的資料
String itemString = (String) parent.getAdapter().getItem(position);
Pattern pattern = Pattern.compile("^(\\S+) (.*)$");
Matcher matcher = pattern.matcher(itemString);
String boardName="", boardTitle="";
if(matcher.find()){
boardName = matcher.group(1);
boardTitle = matcher.group(2);
}
Intent intent = new Intent(this, TextListActivity.class);
intent.putExtra("boardName", boardName);
intent.putExtra("boardTitle", boardTitle);
startActivity(intent);
}
因為是 ArrayAdapter,使用 getItem() 取得的資料只有一個 String
這個 String 之前是用 boardName + " " + boardTitle 存進去的
所以要用正規表示式的方法,再把他還原成兩個字串
正規表示式 Pattern.compile("^(\\S+) (.*)$");
^(\\S+) 的意思是要將開頭為一個以上非空白字元的字串存進 Group 1
接著空一格
(.*)$ 代表將之後一直到結尾的任意字串存進 Group 2
接著用 pattern.matcher(itemString); 輸入要辨識的文字
然後用 matcher.find() 判斷是否有辨識成功
取出 Group 裡的字串存到 boardName, boardTitle
最後用 Intent 加入 boardName, boardTitle 後
跳至看板的 TextListActivity 頁面
修改列表的字體樣式
列表預設的字體顏色是灰色的,如果想要改成白色的話
可以複寫 ArrayAdapter 的 getView()
或是將 android.R.layout.simple_list_item_1
改為自己建立的 xml 資源檔也可以
複寫 getView() 的方法
將 mSearchAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mSearchList);
改為
mSearchAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mSearchList) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
TextView text = (TextView) view.findViewById(android.R.id.text1);
text.setTextColor(Color.WHITE);
return view;
}
};
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
TextView text = (TextView) view.findViewById(android.R.id.text1);
text.setTextColor(Color.WHITE);
return view;
}
};
自建 xml 資源檔的方法
在 /res/layout 新增 Layout resource file
名稱輸入 row_boardsearch
將內容改為
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textColor="#FFF"
android:textSize="20sp"
android:paddingLeft="16dp"
android:minHeight="40dp" />
然後將 android.R.layout.simple_list_item_1 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textColor="#FFF"
android:textSize="20sp"
android:paddingLeft="16dp"
android:minHeight="40dp" />
改為 R.layout.row_boardsearch
加上 HeaderView
在列表的上方加個文字說明,像這樣
![[圖]](http://i.imgur.com/3qG99nj.png)
在 /res/values/strings.xml 加上
<string name="boardSearchHeader">搜尋結果</string>
在 /res/layout 新增 Layout resource file
名稱輸入 row_boardsearchheader
將內容改為
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#555">
<TextView android:id="@+id/header_boardsearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:textColor="#CCC"
android:text="@string/boardHistoryHeader"/>
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#555">
<TextView android:id="@+id/header_boardsearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:textColor="#CCC"
android:text="@string/boardHistoryHeader"/>
</RelativeLayout>
修改類別的程式檔
在 onCreate() 裡,這行 mListView = (ListView) findViewById(R.id.listview); 下面加上
View headerView = getLayoutInflater().inflate(R.layout.row_boardsearchheader, mListView, false);
mListView.addHeaderView(headerView);
mListView.addHeaderView(headerView);
--
※ 作者: Knuckles 時間: 2016-01-26 17:46:04
※ 編輯: Knuckles 時間: 2017-01-16 00:00:57
※ 看板: KnucklesNote 文章推薦值: 0 目前人氣: 0 累積人氣: 2032
回列表(←)
分享