上一篇“查缺補漏”總結了Toolbar的用法,這次我們來看一看ListView。
或許很多人會認為Android出了RecyclerView之後就不用再去了解ListView了,但實際上,ListView作為一種展示清單的控件,曾經在很多的APP中大量的使用,在很多場景中都是很經典的,而且了解了ListView,也會更容易了解RecyclerView。
什麼是ListView
ListView是Android開發中非常重要的基礎元件之一,它使得開發者能夠很容易的展示一組資料。一般而言,實作一個ListView通常需要三個部分:ListView控件、Data資料、Adpter擴充卡,通過擴充卡實作将資料綁定到ListView裡面的控件中。
基本用法
和其他控件一樣,ListView需要先在布局檔案中聲明(當然特殊情況下也可以直接在Java中建立對象)
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
然後在相應的Acrivity中進行綁定
mListView = (ListView)findViewById(R.id.listview);
之後,建立一些資料,這裡我們需要使用ArrayList對資料進行管理
List<Map<String, String>> datas = new ArrayList<Map<String,String>>();
Map<String,String> map1 = new HashMap<String,String>();
map1.put("key","item1");
datas.add(map1);
Map<String,String> map2 = new HashMap<String,String>();
map2.put("key","item2");
datas.add(map2);
建立一個SimpleAdapter将資料放到listView中
mListView.setAdapter(new SimpleAdapter(this,datas,android.R.layout.simple_list_item_1,
new String[]{"key"},
new int[]{android.R.id.text1}
));
這樣一個最基本的ListView就完成了
在上面的代碼中,可以看到在建立SimpleAdapter的時候,傳入了一個R.layout.simple_list_item_1的參數,這個參數用來确定item中展示的樣式,除了simple_list_item_1以外,還有一些其他的樣式。
樣式simple_list_item_2
simple_list_item_2是一種包含副标題的樣式,用法和simple_list_item_1類似,我們在設定資料的時候增加一個參數
List<Map<String, String>> datas = new ArrayList<Map<String,String>>();
Map<String,String> map1 = new HashMap<String,String>();
map1.put("key1","item1");
map1.put("key2","value1");
datas.add(map1);
Map<String,String> map2 = new HashMap<String,String>();
map2.put("key1","item2");
map2.put("key2","value1");
datas.add(map2);
建立一個新的SimpleAdapter,設定為simple_list_item_2
mListView.setAdapter(new SimpleAdapter(this,datas,android.R.layout.simple_list_item_2,
new String[]{"key1","key2"},
new int[]{android.R.id.text1,android.R.id.text2}
));
其中key1和key2的值分别對應android.R.id.text1和android.R.id.text2
樣式simple_list_item_checked
simple_list_item_checked是一種選擇的樣式,用法和simple_list_item_1相似,也隻需設定一個key
mListView.setAdapter(new SimpleAdapter(this,datas,android.R.layout.simple_list_item_checked,
new String[]{"key1"},
new int[]{android.R.id.text1}
));
但是需要設定選擇的模式
/*
* CHOICE_MODE_SINGLE 單選--ListView中隻能有一個item被選中
* CHOICE_MODE_MULTIPLE 多選--允許選中多個item
* CHOICE_MODE_NONE 預設值,點選沒反應
*/
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
除此之外,還有simple_list_item_multiple_choice,simple_list_item_single_choice,可以實作其他的選擇樣式。
自定義布局
很多時候,這些自定義布局并不能滿足我們的需求,那麼便需要我們自己定義item的布局。比如我們建立一個布局檔案名為list_item.xml,裡面放了一個高度為150dp的TextView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="150dp">
<TextView
android:gravity="center"
android:id="@+id/text"
android:text="asd"
android:layout_width="match_parent"
android:layout_height="150dp" />
</LinearLayout>
然後在activity中建立SimpleAdapter
mListView.setAdapter(new SimpleAdapter(this,datas,R.layout.list_item,
new String[]{"key1"},
new int[]{R.id.text}
));
就可以在ListView中看到我們自定義的布局
自定義擴充卡
雖然自定義了布局,但是在很多時候使用SimpleAdapter并不能滿足我們的需求,我們可以通過自己定義擴充卡的方式實作我們期望的各種效果,比如我們再次實作上圖的效果,建立一個繼承BaseAdapter的擴充卡
package com.example.steveyg.listdemo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
/**
* Created by steveyg on 17/1/16.
*/
public class MyAdapter extends BaseAdapter{
//資料集
String []datas = {"item1","item2"};
Context context;
public MyAdapter(Context context){
this.context = context;
}
@Override
public int getCount() {
return datas.length;
}
@Override
public Object getItem(int position) {
return datas[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater li = LayoutInflater.from(context);
TextView tv = (TextView) li.inflate(R.layout.list_item, null);
tv.setText(datas[position]);
return tv;
}
}
在這個擴充卡裡面重寫5個方法,通過view的方式生成view進行處理,這樣就可以使得item更加複雜,實作更多的效果,甚至可以傳回不同的樣式。而資料集datas也可以使用List的方式傳入,更加的靈活。
ViewHolder
當ListView裡面的資料特别多的時候,如果每次都重新建立一個View的話,會占用大量記憶體,對性能造成影響,是以我們需要通過重新填充的方式減少對象的建立。
圖檔來自網絡 修改我們的Adapter
package com.example.steveyg.listdemo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* Created by steveyg on 17/1/16.
*/
public class MyAdapter extends BaseAdapter {
//資料集
String[] datas = {"item1", "item2"};
Context context;
public MyAdapter(Context context) {
this.context = context;
}
@Override
public int getCount() {
return datas.length;
}
@Override
public Object getItem(int position) {
return datas[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = LinearLayout.inflate(context, R.layout.list_item, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.textview.setText(datas[position]);
return convertView;
}
class ViewHolder {
TextView textview;
public ViewHolder(View view) {
this.textview = (TextView) view.findViewById(R.id.text);
}
}
}
這樣便實作了view holder對于adapter的優化。
點選事件
ListView的點選事件可以通過listview實作也可以通過adaper設定,如果使用了SimpleAdapter則需要通過listview實作:
//點選事件
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//點選了第position個item
}
});
//長按事件
mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
return false;
}
});
而如果通過adapter設定,那麼直接在getView中設定各個控件的點選事件即可。