目錄
前言
相關屬性及方法
設定分割線
設定表頭表尾
ArrayAdapter示例
SimpleAdapter示例
BaseAdapter示例
2019.9.4 新增補充:
設定分割線及表頭表尾部分
使用的 Demo 是 BaseAdapter示例 ,如果看不懂可以 先過下屬性和方法,等看到 BaseAdapter 再回來看例程
放心,我會放傳送門的!
前言
ListView 在 Android 衆多控件中占有比較重要的地位,通常用于顯示垂直滾動列。
Google 在釋出的 v7相容包 中提出了新的控件RecyclerView,可代替ListView。這個後面再學,先搞定ListView,畢竟内容也不少,一步步慢慢來。
一個ListView通常都有三個要素組成:
- ListView控件
- 擴充卡類,用到了設計模式中的擴充卡模式,它是視圖和資料之間的橋梁,負責提供對資料的通路,生成每一個清單項對于的View。
- 資料源,當然最重要最複雜的部分就是擴充卡類的編寫和設計,在一些複雜的界面,常常需要對擴充卡類進行相關邏輯處理。
相關屬性及方法
設定分割線
相關屬性
footerDividersEnabled 是否在footerView(表尾)前繪制一個分隔條,預設為true
headerDividersEnabled 是否在headerView(表尾)前繪制一個分隔條,預設為true
divider 設定分隔條,可以用顔色分割,也可以用drawable資源分割
dividerHeigh 設定分隔條的高度
示例
在 BaseAdapter示例 的基礎上,修改 activity_list_view.xml,給 ListView 添加屬性即可
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ListViewActivity"
android:padding="10dp">
<ListView
android:id="@+id/id_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#8888"
android:dividerHeight="5dp">
</ListView>
</LinearLayout>
效果圖
設定表頭表尾
相關java方法
addHeaderView(View v) 添加headView(表頭),括号中的參數是一個View對象
addFooterView(View v) 添加footerView(表尾),括号中的參數是一個View對象
addHeaderView(headView, null, false) 和前面的差別:設定Header是否可以被選中
addFooterView(View,view,false) 同上
示例
在 BaseAdapter示例 的基礎上,添加表頭表尾xml
activity_listview_header.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="表頭"
android:textSize="18sp"
android:textAlignment="center"
android:textColor="#FFF"
android:background="#F00"/>
</LinearLayout>
activity_listview_foot.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="表尾"
android:textSize="18sp"
android:textAlignment="center"
android:textColor="#000"
android:background="#888"/>
</LinearLayout>
在 ListViewActivity.java 中添加以下代碼
//動态加載ListView表頭表尾
final LayoutInflater inflater = LayoutInflater.from(this);
View headView = inflater.inflate(R.layout.activity_listview_header,null,false);
View foodView = inflater.inflate(R.layout.activity_listview_foot,null,false);
listView.addHeaderView(headView);
listView.addFooterView(foodView);
注意:這部分代碼應該添加到 setAdapter 之前。
此外,設定表頭後,表頭将成為 listView 的第一項,是以我後面點選表頭,它卻說它叫紅紅...
效果圖
ArrayAdapter示例
activity_list_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ListViewActivity"
android:padding="10dp">
<ListView
android:id="@+id/id_listview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
ListViewActivity.java
package com.example.my_test;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
public class ListViewActivity extends AppCompatActivity {
private String data[] = {"紅紅","橙橙","黃黃","綠綠","蘭蘭","紫紫","粉粉","灰灰","屎屎"};
private ListView one_ListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
one_ListView = (ListView)findViewById(R.id.id_listview);
//建立并設定擴充卡
final ArrayAdapter <String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
data);
one_ListView.setAdapter(adapter);
//監聽事件
one_ListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(ListViewActivity.this,
"我是"+ adapter.getItem(i),
Toast.LENGTH_SHORT).show();
}
});
}
}
效果圖
SimpleAdapter示例
前面學習 擴充卡 的時候說到,ArrayAdapter 适用于顯示資訊比較單一的場景,若清單項中包含多種形式的資料,就不太适用了。
因而,我們這裡使用 SimpleAdapter 。
activity_listview_item.xml(子項目布局)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|left">
<ImageView
android:id="@+id/id_listview_item_image"
android:src="@drawable/user1"
android:layout_width="100dp"
android:layout_height="100dp"/>
<TextView
android:id="@+id/listview_item_name"
android:text="紅紅"
android:gravity="center"
android:layout_marginLeft="50dp"
android:textSize="50sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
activity_list_view.xml(主布局)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ListViewActivity"
android:padding="10dp">
<ListView
android:id="@+id/id_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
ListViewActivity.java
package com.example.my_test;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ListViewActivity extends AppCompatActivity {
private ListView listView;
private SimpleAdapter simpleAdapter;
private List<Map<String,Object>> datas = new ArrayList<Map<String,Object>>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
listView = (ListView)findViewById(R.id.id_list_view);
//添加資料
Init_datas();
//設定擴充卡
simpleAdapter = new SimpleAdapter(this,
datas,
R.layout.activity_listview_item,
new String[]{"img","name"},
new int[]{R.id.id_listview_item_image,R.id.listview_item_name});
listView.setAdapter(simpleAdapter);
}
private void Init_datas(){
Map map1 = new HashMap();
map1.put("img",R.drawable.user1);
map1.put("name","紅紅");
datas.add(map1);
Map map2 = new HashMap();
map2.put("img",R.drawable.user2);
map2.put("name","橙橙");
datas.add(map2);
Map map3 = new HashMap();
map3.put("img",R.drawable.user3);
map3.put("name","黃黃");
datas.add(map3);
Map map4 = new HashMap();
map4.put("img",R.drawable.user4);
map4.put("name","綠綠");
datas.add(map4);
Map map5 = new HashMap();
map5.put("img",R.drawable.user5);
map5.put("name","蘭蘭");
datas.add(map5);
Map map6 = new HashMap();
map6.put("img",R.drawable.user6);
map6.put("name","紫紫");
datas.add(map6);
Map map7 = new HashMap();
map7.put("img",R.drawable.user7);
map7.put("name","粉粉");
datas.add(map7);
Map map8 = new HashMap();
map8.put("img",R.drawable.user8);
map8.put("name","灰灰");
datas.add(map8);
Map map9 = new HashMap();
map9.put("img",R.drawable.user9);
map9.put("name","屎屎");
datas.add(map9);
}
}
SimpleAdapter的構造函數如下: SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)
我們執行個體化SimpleAdapter時傳入的參數分别是:
- context:即上下文對象,這裡傳入this;
- data:是一個包裹Map集合的List資料集,這裡傳入datas,程式初始化的資料集;
- resource:子項布局檔案,這裡是我們自定義的activity_listview_item.xml檔案,傳入R.layout.activity_listview_item;
- from:是一個字元串數組,字元串指的是Map中的鍵值,這裡有兩個鍵,即“img”和“name”;
to:是一個int型數組,表示子項布局中對應控件的id,這裡傳入ImageView的ID R.id.id_listview_item_image
和TextView的ID R.id.listview_item_name 即可。
效果圖
BaseAdapter示例
BaseAdapter 是 SimpleAdapter 的父類,較 SimpleAdapter 來講更為靈活。之前再學習擴充卡的時候沒有使用到,這裡補上。
BaseAdapter 使用方法
1.建立一個 java 檔案 ManAdapter.java,繼承自 BaseAdapter,并且實作它的 4 個基礎方法。這四個方法分别是:提示:可以簡單的了解為,adapter 先從 getCount ( ) 裡确定數量,然後循環執行 getView ( ) 方法将條目一個一個繪制出來,是以必須重寫的是 getCount ( ) 和 getView ( ) 方法。而 getItem ( ) 和 getItemId ( ) 是調用某些函數才會觸發的方法。
- getCount ( ) : 傳回子項的數目,比如格子的數量
- getItem ( ) : 根據一個索引(位置)獲得該位置的對象,傳回子項下标對應的對象
- getItemId ( ) : 擷取條目的 id,傳回子項下标
- getView ( ): 擷取該條目要顯示的界面,傳回子項視圖
2.ManAdapter 這個類寫好後,我們就建立一個 manAdapter。manAdapter = new ManAdapter(ListViewActivity.this,datas);
3.在 ListView的 view 中,使用 setAdapter 方法傳入我們的 manAdapter 就可以用了。listView.setAdapter(manAdapter);
示例
例程中使用了自定義布局,因而我還建立額一個 Man.java 作為每個子項要展示的内容
若子布局隻需要展示 TextView 這類的資料,ManAdapter.java中将datas類型修改。
Man.java
package com.example.my_test;
public class Man {
private String name;
private int imageId;
public Man(String name,int imageId){
this.name = name;
this.imageId = imageId;
}
public String getName(){
return name;
}
public int getImageId(){
return imageId;
}
}
ManAdapter.java
package com.example.my_test;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class ManAdapter extends BaseAdapter {
private Context context;
private List<Man> datas;
//構造函數
public ManAdapter(Context context,List<Man> datas){
this.context = context;
this.datas = datas;
}
//傳回子項個數
@Override
public int getCount(){
return datas.size();
}
//傳回子項下标
@Override
public long getItemId(int position){
return position;
}
//傳回子項下标對應的對象
@Override
public Object getItem(int position){
return datas.get(position);
}
//傳回子項視圖
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//最慢的加載方法
// 每次調用 getView () 的時候都去通過 findViewById 執行個體化控件
// 因而這裡的控件必須将Image View 的android:src設定為空或者不設定(預設為空)
// 同理,Text View 的android:text 屬性也應該同樣設定
convertView = LayoutInflater.from(context).inflate(R.layout.activity_listview_item,null);
ImageView img_ico = (ImageView)convertView.findViewById(R.id.id_listview_item_image);
TextView name = (TextView)convertView.findViewById(R.id.listview_item_name);
img_ico.setBackgroundResource(datas.get(position).getImageId());
name.setText(datas.get(position).getName());
return convertView;
}
}
ListViewActivity.java
package com.example.my_test;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class ListViewActivity extends AppCompatActivity {
private ListView listView;
private ManAdapter manAdapter = null;
private List<Man> datas = new ArrayList<Man>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
initDatas();
listView = (ListView)findViewById(R.id.id_list_view);
manAdapter = new ManAdapter(ListViewActivity.this,datas);
listView.setAdapter(manAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(ListViewActivity.this,
"我是"+ datas.get(i).getName(),
Toast.LENGTH_SHORT).show();
}
});
}
private void initDatas(){
Man man1 = new Man("紅紅",R.drawable.user1);
Man man2 = new Man("橙橙",R.drawable.user2);
Man man3 = new Man("黃黃",R.drawable.user3);
Man man4 = new Man("綠綠",R.drawable.user4);
Man man5 = new Man("蘭蘭",R.drawable.user5);
Man man6 = new Man("紫紫",R.drawable.user6);
Man man7 = new Man("粉粉",R.drawable.user7);
Man man8 = new Man("灰灰",R.drawable.user8);
Man man9 = new Man("屎屎",R.drawable.user9);
datas.add(man1);
datas.add(man2);
datas.add(man3);
datas.add(man4);
datas.add(man5);
datas.add(man6);
datas.add(man7);
datas.add(man8);
datas.add(man9);
}
}
可以發現,getView( )每次都調用了findViewByld方法,而除了第一次調用給它綁定上外,我們的Item大多數情況下都是一樣的,是以我們可以改寫getView( )方法
package com.example.my_test;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class ManAdapter extends BaseAdapter {
private Context context;
private List<Man> datas;
//構造函數
public ManAdapter(Context context,List<Man> datas){
this.context = context;
this.datas = datas;
}
//傳回子項個數
@Override
public int getCount(){
return datas.size();
}
//傳回子項下标
@Override
public long getItemId(int position){
return position;
}
//傳回子項下标對應的對象
@Override
public Object getItem(int position){
return datas.get(position);
}
//傳回子項視圖
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 改進1:當 convertView 不為空的時候直接重新使用 convertView 進而減少了很多不必要的 View 的建立
// 改進2:使用 ViewHolder 模式提高效率
// 将 convertView 的 tag 設定為 ViewHolder, 不為空時重新使用即可 (最快的加載方式)
Man man =(Man)getItem(position);
View view;
ViewHolder viewHolder;
if(convertView == null){
view = LayoutInflater.from(context).inflate(R.layout.activity_listview_item,null);
viewHolder = new ViewHolder();
viewHolder.manImage = (ImageView)view.findViewById(R.id.id_listview_item_image);
viewHolder.manName = (TextView)view.findViewById(R.id.listview_item_name);
view.setTag(viewHolder);
}
else{
view = convertView;
viewHolder = (ViewHolder)view.getTag();
}
viewHolder.manName.setText(man.getName());
viewHolder.manImage.setImageResource(man.getImageId());
return view;
}
//建立ViewHolder類
class ViewHolder{
ImageView manImage;
TextView manName;
}
}
注意:
- activity_listview_item.xml(子項目布局)與 activity_list_view.xml(主布局)均未改動。
- 自行添加java檔案後,需要在 app -> main -> AndroidManifest.xml 中添加
- 使用未優化的 getView () 方法時,每次都會執行個體化控件,因而這裡的控件必須将Image View 的 android:src 屬性設定為空或者不設定(預設為空),Text View 控件的 android:text 屬性也是同樣的道理。否則畫面會有疊加的效果。
效果圖
可以回過頭看 設定分割線 設定表頭表尾 的例程喲~
最後推薦幾篇不錯的博文:
BaseAdapter的使用
ListView的簡單應用
菜鳥教程 ListView
ListView 使用技巧