安卓學習筆記--ListView、自定義配接器、模糊查找、RecyclerView
- ListView的基本使用
- 最簡單的ListView
- 為ListView設定點擊事件
- 自定義配接器
- 模糊查找
ListView的基本使用
最簡單的ListView

這是一個最簡單的List View,創建很簡便,但是缺點也很明顯,僅僅只能適配一個字串,現在就來看看如何創建這個最簡單的配接器
1.在布局檔案中添加List View
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
2.在主活動中,系結這個控制元件,在主活動的onCreate()方法里面:
ListView listView = (ListView)this.findViewById(R.id.list_view);
3.在主活動中,創建一個ArrayAdapter配接器,對其實體化,然后讓其和List View進行系結: 寫在onCreate()方法里面
// 以下是很簡單的通過ArrayAdapter配接器來適配一個串列,缺點是一行只能適配一個文本
String[] data= {"apple","banana","origin","pear"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
MainActivity.this, //背景關系
android.R.layout.simple_list_item_1, //串列布局采用系統樣式1
data //串列資料來源字串陣列data
);
listView.setAdapter(adapter);
①data 字串陣列,用于存放每一個子項的文本,
②實體化一個ArrayAdapter配接器,這里使用它帶有3個引數的建構式,第一個引數是context,是配接器的背景關系環境,代表在哪個活動適配, 第二個引數是一個樣式,這里使用系統自帶的一個樣式android.R.layout.simple_list_item1 第三個引數串列的資料來源,為字串陣列型別,
③配接器創建好以后,就可以將其和List View系結到一起,利用ListView的setAdapter()方法,把這個配接器和ListView系結到一起,這樣就可以顯示出上圖的效果,
3-2.ArrayAdapter的另一種構造方法:
如果你不滿足于系統提供給你的樣式,也可以使用自己的樣式,
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
MainActivity.this, //背景關系
R.layout.stu_list, //串列布局檔案
R.id.custom_textview, //串列布局檔案里面的一個TextView控制元件
data //適配的資料
);
這是帶四個引數的建構式,可以發現,這里面有兩個地方和上面的不一樣,第二個引數是你自己寫的layout布局檔案,而第三個引數,是這個布局檔案里面的一個控制元件,這樣,資料源的文本就會顯示到這個指定的控制元件上,而ListView的每一個子項,都是你這個布局檔案,
這種帶四個引數的建構式,比起上面的那一個,多了一個自己的布局檔案,你可以顯示文本資訊要寫在哪一個地方,但是缺點還是只能適配一個字串,對比上面的那個,就是單純的好看一點吧,
4.當適配的內容發生變化的時候,通知配接器進行更新:
當你的串列資料源發生了改變,這時候就需要通知配接器所適配的內容需要改變了,具體的顯示就是你可以看到新的ListView內容,
比如下面這樣:
data[0] = "mmm";
adapter.notifyDataSetChanged(); //修改資料源以后更新配接器,動態重繪串列
在上例基礎上,把字串陣列的第一個元素值改變為"mmm",這時候,就可以使用配接器的notifyDataSetChanged()方法,通知配接器更新,實作動態重繪的效果,
為ListView設定點擊事件
有了ListView顯示出來以后,還需要為其設定點擊事件,當點擊不同的子項的時候,有不同的反應,如果僅僅可以看,那有什么用呢?
在主活動的onCreate()方法里面,加入如下代碼:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String item = adapter.getItem(i);
Toast.makeText(MainActivity.this, item, Toast.LENGTH_SHORT).show();
}
});
使用ListView的setonItemClickListerner可以實作對串列視圖當個子項點擊的事件監聽,這上面的代碼中,重寫onItemClick方法,實作點擊子項彈出顯示對應文本,
!!注意:如果你想要獲得子項的內容,比如上面我就獲得了一個串列視圖的資料源字串,我建議你使用配接器的getItem(i)來獲得子項,或許你也可以用List<> 的get()方法,但是并不推薦這樣使用,因為如果是List的get方法,這個List你寫在主活動里面,如果你進行了模糊查找等,配接器里面的List發生了改變,但是你任然使用List的getItem方法來獲得,那么就會出現不對應的問題,
好像有點而繞,總之,只要記得推薦使用配接器提供的getItem方法來獲得子項,這樣是最好的方法,

自定義配接器
上面的ListView,是使用最簡單的配接器系結的,它有一個不足,那就是所能適配的僅僅只有一個文本資訊,但是,通常我們的子項,可能有多個TextView,有多個ImageView等,需要對不同的TextView適配不同的內容,這個時候,就需要用到自定義的配接器了,
自定義的配接器,簡單來說,需要有3個檔案:
1.子項的布局檔案、2.所需要適配的資料源類、3.自定義的配接器類
舉個示例,現在我們來實作一下下面這個圖片的ListView

可以看到,每一個子項,都有一個卡號、型別、金額、日期需要進行適配,前面所用的適配,已經完全不能夠滿足我們的需要,那么,現在開始自定義的配接器:
1.新建一個布局檔案,用于子項的布局:
<?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="120dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:orientation="vertical"
>
<TextView
android:id="@+id/tv_idCard"
android:text="卡號:1234567890123456"
android:textSize="18sp"
android:layout_width="wrap_content"
android:layout_height="20dp" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_leixing"
android:text="型別:轉賬"
android:textSize="18sp"
android:layout_alignParentRight="true"
android:gravity="left"
android:layout_toRightOf="@+id/tv_idCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<TextView
android:id="@+id/tv_jiner"
android:text="金額:1000000.00"
android:textSize="18sp"
android:layout_alignParentRight="true"
android:gravity="left"
android:layout_toRightOf="@+id/tv_idCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
</LinearLayout>
<TextView
android:id="@+id/tv_day"
android:text="日期:2020-12-11-12-56-04"
android:textSize="18sp"
android:gravity="right"
android:layout_below="@+id/tv_idCard"
android:layout_toRightOf="@+id/tv_idCard"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="20dp" />
<View
android:id="@+id/vw_Line_password"
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="#83738F"
android:layout_below="@id/tv_day"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
/>
</LinearLayout>
上面的布局檔案代碼,你不必要詳細的看,我們只需要知道自定義的配接器如何實作,這里僅僅貼出來,
2.自定義一個資料源類:
public class JiaoYi {
private String bankId; //交易卡號
private String type; //型別
private float money; //金額
private String day; //日期
private String targetBankId=""; //目標賬戶卡號,僅在轉賬的時候會被賦值
JiaoYi(String id,String ty,float mo,String d){
this.bankId = id;
this.type = ty;
this.money = mo;
this.day = d;
}
public void setTargetBankId(String t){this.targetBankId = t;}
public String getTargetBankId(){return this.targetBankId;}
public String getBankId(){return this.bankId;}
public String getType(){return this.type;}
public float getMoney(){return this.money;}
public String getDay(){return this.day;}
}
這一個類的作用,是包括了你所需要的適配的內容,比如我們這里所需要適配的內容,有卡號、型別、金額、日期,那么我們這里就寫了一個交易類,這個類保存了上述所需要的資訊,
3.自定義配接器,實作系結視圖和獲得適配內容:
新建一個類,繼承于BaseAdapter,然后實作其6個重要的方法
右擊包名–新建一個class ,手動添加繼承 extends BaseAdapter ,這個時候你會發現有紅色波浪線,點擊波浪線處,等待一會有個小燈泡,選擇小燈泡就會看到一個繼承基類的方法,那些方法就是必須要實作的方法,

點擊小燈泡,implement method

見名知意,
getCount 是得到適配的數量,即有多個子項
getItem 是得到子項,即回傳所適配的子項
getItemId 是得到子項的id號
getView 是得到子項的視圖,用于每一個子項在顯示的時候如何進行顯示
分析完畢,現在讓我們看一下具體的代碼吧:
class JiaoyiAdapter extends BaseAdapter {
private List<JiaoYi> list_jiaoyi; //用于顯示資料
private List<JiaoYi> list_forRemember; //用于備份全部資料
private LayoutInflater inflater;
private JiaoyiFilter jiaoyiFilter;
private class ViewHolder{
TextView kahao,type,money,day; //卡號,型別,金額,日期
}
JiaoyiAdapter(Context context,List<JiaoYi> m){
this.list_jiaoyi = m;
this.list_forRemember = list_jiaoyi;
this.inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return list_jiaoyi.size();
}
@Override
public Object getItem(int i) {
return list_jiaoyi.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
JiaoYi temp = list_jiaoyi.get(i);
ViewHolder viewHolder = null;
if (view == null){
view = inflater.inflate(R.layout.listview_jiaoyi,null);
viewHolder = new ViewHolder();
viewHolder.kahao = (TextView)view.findViewById(R.id.tv_idCard);
viewHolder.type = (TextView)view.findViewById(R.id.tv_leixing);
viewHolder.money = (TextView)view.findViewById(R.id.tv_jiner);
viewHolder.day = (TextView)view.findViewById(R.id.tv_day);
view.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.kahao.setText("卡號:"+temp.getBankId());
viewHolder.type.setText("型別:"+temp.getType());
viewHolder.money.setText("金額:"+String.valueOf(temp.getMoney()));
viewHolder.day.setText("日期:"+temp.getDay());
return view;
}
}
分析:
①首先來看一下建構式,這個是必須要寫的,
JiaoyiAdapter(Context context,List<JiaoYi> m){
this.list_jiaoyi = m;
this.list_forRemember = list_jiaoyi;
this.inflater = LayoutInflater.from(context);
}
一般是寫一個帶兩個引數的建構式即可,第一個引數是context 背景關系,第二個引數是一個List型別,是你要適配的資料源,在建構式中,把外部的context和List賦值給自己的成員變數,這里面使用到了一個成員變數LayoutInflater型別的inflater,這個是用于在后面動態加入布局,
②重寫getCount,getItem,getItemId
@Override
public int getCount() {
return list_jiaoyi.size();
}
@Override
public Object getItem(int i) {
return list_jiaoyi.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
從上面的分析,可以知道,
我們要適配的資料源是List串列里面的每一個元素,那么getCount這個方法回傳的適配的數量,就是這個List的size
getItem需要獲得每一個適配子項,這每一個子項,就是List對應的每一個元素,可以通過List的get方法,直接獲得
getItemId方法,是得到子項的Id號,因為子項的id就是List的id,所以這里直接回傳i即可,
③重寫getView方法,這個方法是最最至關重要的,從它的回傳值是一個view型別,我們可以知道,這個方法,解決的是每一個子項的view,即這個子項是如何顯示的(在哪個context里面顯示?顯示的布局是什么樣子的?所需要適配的又是什么?)
在寫這個方法之前,我們先寫一個私有類ViewHolder
private class ViewHolder{
TextView kahao,type,money,day; //卡號,型別,金額,日期
}
這個私有類,里面包含該配接器所需要適配的所有控制元件,因為我們這里需要適配的卡號、型別、金額、日期,是分別在4個不同的TextView里面,那么我們就需要4個TextView控制元件,
現在,開始重寫這個getView方法
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
JiaoYi temp = list_jiaoyi.get(i);
ViewHolder viewHolder = null;
if (view == null){
view = inflater.inflate(R.layout.listview_jiaoyi,null);
viewHolder = new ViewHolder();
viewHolder.kahao = (TextView)view.findViewById(R.id.tv_idCard);
viewHolder.type = (TextView)view.findViewById(R.id.tv_leixing);
viewHolder.money = (TextView)view.findViewById(R.id.tv_jiner);
viewHolder.day = (TextView)view.findViewById(R.id.tv_day);
view.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.kahao.setText("卡號:"+temp.getBankId());
viewHolder.type.setText("型別:"+temp.getType());
viewHolder.money.setText("金額:"+String.valueOf(temp.getMoney()));
viewHolder.day.setText("日期:"+temp.getDay());
return view;
}
先來看一下這個getView方法,所帶有的四個引數,
1.i 這個i其實就是position位置,即現在是哪一個子項進行getView操作
2.view 視圖,每一個子項,都有其自己的一個view,呼叫這個方法,最后回傳的view,就是告訴配接器,這個子項最終顯示的樣子是什么樣的
3.ViewGroup 視圖組,這個我們這里暫時不用到,
回顧一下前面說的,在哪個context里面顯示?顯示的布局是什么樣子的?所需要適配的又是什么?現在就來一一解決這些問題
1.view = inflater.inflate(R.layout.listview_jiaoyi,null);
通過這一行代碼,為這個子項的view加入需要顯示的布局,背景關系context之前在建構式中已經指明了,
2.
viewHolder = new ViewHolder();
viewHolder.kahao = (TextView)view.findViewById(R.id.tv_idCard);
viewHolder.type = (TextView)view.findViewById(R.id.tv_leixing);
viewHolder.money = (TextView)view.findViewById(R.id.tv_jiner);
viewHolder.day = (TextView)view.findViewById(R.id.tv_day);`
這一部分代碼,實體化一個ViewHolder類,然后把里面的TextView和布局檔案里面的控制元件一一系結,
3.
JiaoYi temp = list_jiaoyi.get(i);
viewHolder.kahao.setText("卡號:"+temp.getBankId());
viewHolder.type.setText("型別:"+temp.getType());
viewHolder.money.setText("金額:"+String.valueOf(temp.getMoney()));
viewHolder.day.setText("日期:"+temp.getDay());
這一部分的代碼,解決了前面4個控制元件所需要適配顯示的具體文本資訊,首先定義一個資料源類物件temp ,從List的get方法為其實體化,然后就可以進行下面的具體賦值操作了,
4.最后,看最完整的getView,為什么要使用一個私有類ViewHolder?為什么要對view進行if(view == null)這樣的判斷呢?
因為在ListView顯示的時候,如果有很多的資料,而我們上下滑動翻動的速度過快,那么配接器就會不停的進行getView方法,為了讓效率提高,這里使用一個私有類ViewHolder,里面先系結了需要適配的具體控制元件,這樣就可以提高一點速度,其次,因為每一個getView,本身都會傳入一個view引數,如果每一次進行getView,都要重寫回傳一個新的view,那樣勢必會造成記憶體的大量浪費,所以,我們可以通過view.setTag方法,可以把ViewHolder放入,當下一次呼叫這個子項的getView的時候,先判單一下view是否為空,如果不為空,就說明之前已經對其初始化一次了,那么就可以通過getTag方法,從里面取得ViewHolder,然后對里面的控制元件進行賦值操作,
模糊查找
如果是自定義的配接器,就需要自定義一個Filter類來實作模糊查找,
在剛剛的交易配接器類里面,再添加一個自定義類
class JiaoyiFilter extends Filter{
//在下面這個方法中定義過濾的規則
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
FilterResults results = new FilterResults(); //過濾結果
List<JiaoYi> list; //用于存放交易的結果
if (TextUtils.isEmpty(charSequence)){
list = list_forRemember; //如果過濾內容為空則顯示全部,把備份的資料替換進去
}else {
list = new ArrayList<JiaoYi>();
for (JiaoYi jiaoYi:list_forRemember){ //遍歷的物件是備份list 這里面才是全部元素
//下面是過濾的規則 從JiaoYi物件里面獲得匹配內容然后判斷是否contains過濾文本
if (jiaoYi.getBankId().contains(charSequence)){
list.add(jiaoYi);
}
}
}
results.values = list; //設定value 為list
results.count = list.size(); //設定大小
return results;
}
//在下面的方法中 通知配接器更新界面
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
list_jiaoyi = (List<JiaoYi>) filterResults.values;
if (filterResults.count>0){
notifyDataSetChanged(); //通知配接器資料已經改變
}else {
notifyDataSetInvalidated(); //通知資料失效
}
}
}
別忘記:
class JiaoyiAdapter extends BaseAdapter implements Filterable
接著,重寫getFilter方法
@Override
public Filter getFilter() {
if (jiaoyiFilter == null){
jiaoyiFilter = new JiaoyiFilter();
}
return jiaoyiFilter;
}
這里面的jiaoyiFilter是前面配接器的成員變數private JiaoyiFilter jiaoyiFilter;
寫好了以后,在主活動里面listView_jiaoyi.setTextFilterEnabled(true);
為ListView啟動過濾,然后就可以在活動里面進行過濾了
adapter_jiaoyi.getFilter().filter(edt_yhk.getText().toString());
如果篩選的條件為空,那么記得使用
adapter_jiaoyi.getFilter().filter("");把過濾清除
比如下面,我在搜索框內為其設定當輸入內容發生改變的時候進行ListView的過濾
edt_yhk.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (TextUtils.isEmpty(edt_yhk.getText().toString())){
//清除過濾
adapter_jiaoyi.getFilter().filter("");
}else {
adapter_jiaoyi.getFilter().filter(edt_yhk.getText().toString());
//list_jiaoyi = adapter_jiaoyi.getList_jiaoyi();
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
到此,基本上都已經講完了,關于自定義的配接器,在主活動里面如何呼叫,這個和前面最簡單的配接器其實是一模一樣的,都是
list_jiaoyi = new ArrayList<JiaoYi>();
listView_jiaoyi = (ListView)findViewById(R.id.lv_jiaoyi);
adapter_jiaoyi = new JiaoyiAdapter(JiaoYiActivity.this,list_jiaoyi);
listView_jiaoyi.setAdapter(adapter_jiaoyi);
初始化所需要資料源List串列
系結ListView控制元件
初始化自定義的配接器,用到context背景關系以及List資料源串列兩個引數
然后為這個ListView系結配接器ListView.setAdapter,
如果要為List添加元素,可以通過List的add方法,或者remove方法來移除某個元素,再通過配接器的notifyDataSetChanged()方法動態重繪,
到此,這一篇關于ListView以及自定義配接器、模糊查找的學習筆記就結束了,本來還想著寫RecyclerView的,但是內容有點長,有點啰嗦,就放在另一篇筆記里面記錄吧,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/238090.html
標籤:其他
