ListView是Android中最常用的控件之一嫉戚,幾乎所有的應(yīng)用程序都會(huì)用到它,因此學(xué)會(huì)運(yùn)用它很重要机蔗。下面我們從一個(gè)例子中去理解ListView的用法背传,先看一下我們這個(gè)例子的項(xiàng)目結(jié)構(gòu)圖
這里我們先看Fruit,F(xiàn)ruitAdapter 和fruit_item這三個(gè)文件
- Fruit是作為L(zhǎng)istView適配器的類(lèi)型
- FruitAdapter是繼承ArrayAdapter的適配器
- fruit_item是ListView的子項(xiàng)布局文件
那么問(wèn)題就來(lái)了谷婆,為什么要有適配器慨蛙?它的作用又是什么呢?
之所以要有適配器是因?yàn)槲覀兊臄?shù)據(jù)不能直接傳遞給ListView纪挎,因此我們需要借助適配器來(lái)完成數(shù)據(jù)的傳遞期贫。而ArrayAdapter是android中比較好用的一種,可以通過(guò)泛型來(lái)指定要適配的數(shù)據(jù)類(lèi)型异袄,然后在構(gòu)造函數(shù)中把要適配的數(shù)據(jù)傳入
下面我們就來(lái)看一下各個(gè)部分的代碼通砍,首先我們來(lái)看一下MainActivity的代碼
package com.example.apple.listviewtest;
import android.support.v7.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 MainActivity extends AppCompatActivity {
// fruitList用于存儲(chǔ)數(shù)據(jù)
private List<Fruit> fruitList=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 先拿到數(shù)據(jù)并放在適配器上
initFruits(); //初始化水果數(shù)據(jù)
FruitAdapter adapter=new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
// 將適配器上的數(shù)據(jù)傳遞給listView
ListView listView=findViewById(R.id.list_view);
listView.setAdapter(adapter);
// 為L(zhǎng)istView注冊(cè)一個(gè)監(jiān)聽(tīng)器,當(dāng)用戶點(diǎn)擊了ListView中的任何一個(gè)子項(xiàng)時(shí)烤蜕,就會(huì)回調(diào)onItemClick()方法
// 在這個(gè)方法中可以通過(guò)position參數(shù)判斷出用戶點(diǎn)擊的是那一個(gè)子項(xiàng)
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fruit fruit=fruitList.get(position);
Toast.makeText(MainActivity.this,fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
}
// 初始化數(shù)據(jù)
private void initFruits(){
for(int i=0;i<10;i++){
Fruit a=new Fruit("a",R.drawable.a);
fruitList.add(a);
Fruit b=new Fruit("B",R.drawable.b);
fruitList.add(b);
Fruit c=new Fruit("C",R.drawable.c);
fruitList.add(c);
Fruit d=new Fruit("D",R.drawable.d);
fruitList.add(d);
}
}
}
代碼也不復(fù)雜封孙,我們直接看注釋就好了
接下來(lái)看一看對(duì)應(yīng)的activity_main.xml的代碼
<?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="match_parent"
>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
這里的代碼也很簡(jiǎn)單,就是用了一個(gè)ListView控件
然后我們就看一下適配器FruitAdapter的代碼
package com.example.apple.listviewtest;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId;
// 適配器的構(gòu)造函數(shù)玖绿,把要適配的數(shù)據(jù)傳入這里
public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects){
super(context,textViewResourceId,objects);
resourceId=textViewResourceId;
}
// convertView 參數(shù)用于將之前加載好的布局進(jìn)行緩存
@Override
public View getView(int position, View convertView, ViewGroup parent){
Fruit fruit=getItem(position); //獲取當(dāng)前項(xiàng)的Fruit實(shí)例
// 加個(gè)判斷敛瓷,以免ListView每次滾動(dòng)時(shí)都要重新加載布局,以提高運(yùn)行效率
View view;
ViewHolder viewHolder;
if (convertView==null){
// 避免ListView每次滾動(dòng)時(shí)都要重新加載布局斑匪,以提高運(yùn)行效率
view=LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
// 避免每次調(diào)用getView()時(shí)都要重新獲取控件實(shí)例
viewHolder=new ViewHolder();
viewHolder.fruitImage=view.findViewById(R.id.fruit_image);
viewHolder.fruitName=view.findViewById(R.id.fruit_name);
// 將ViewHolder存儲(chǔ)在View中(即將控件的實(shí)例存儲(chǔ)在其中)
view.setTag(viewHolder);
} else{
view=convertView;
viewHolder=(ViewHolder) view.getTag();
}
// 獲取控件實(shí)例呐籽,并調(diào)用set...方法使其顯示出來(lái)
viewHolder.fruitImage.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());
return view;
}
// 定義一個(gè)內(nèi)部類(lèi),用于對(duì)控件的實(shí)例進(jìn)行緩存
class ViewHolder{
ImageView fruitImage;
TextView fruitName;
}
}
可以看到在FruitAdapter類(lèi)中我們重寫(xiě)了父類(lèi)的一組構(gòu)造函數(shù)蚀瘸,用于將上下文狡蝶、ListView子項(xiàng)布局的id和數(shù)據(jù)都傳遞進(jìn)來(lái)。另外又重寫(xiě)了getView()方法贮勃,這個(gè)方法在每個(gè)子項(xiàng)被滾動(dòng)到屏幕內(nèi)的時(shí)候會(huì)被調(diào)用贪惹。ListView本身的運(yùn)行效率是很低的,因此我們需要優(yōu)化寂嘉,具體的優(yōu)化方法已經(jīng)在代碼中了奏瞬,直接看代碼注釋就知道了
現(xiàn)在我們?cè)倏纯碏ruit的代碼
package com.example.apple.listviewtest;
public class Fruit {
private String name;
private int imageId;
public Fruit(String name,int imageId){
this.name=name;
this.imageId=imageId;
}
public String getName(){
return name;
}
public int getImageId(){
return imageId;
}
}
Fruit是ListView適配器的類(lèi)型,即是數(shù)據(jù)傳入到ListView中的類(lèi)型泉孩。
public class FruitAdapter extends ArrayAdapter<Fruit>
看這行FruitAdapter中的代碼硼端,我們把Fruit作為了適配器的類(lèi)型
我們最后看一下fruit_item的代碼
<?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="match_parent">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="50dp"
android:layout_height="50dp" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
/>
</LinearLayout>
代碼也不復(fù)雜,每個(gè)子項(xiàng)布局都顯示一張圖片和一段文字
最終效果圖如下:
總結(jié):
使用ListView寓搬,關(guān)鍵是在適配器與適配器的類(lèi)型上珍昨,這兩個(gè)方面掌握了,基本就可以定制出屬于自己的ListView界面了。ListView雖然功能強(qiáng)大镣典,但是它只能實(shí)現(xiàn)縱向滾動(dòng)的效果兔毙,如果要實(shí)現(xiàn)橫向滾動(dòng)就有心無(wú)力了。