ListView是APP中的常用組件之一,它的使用方式與其他組件相比之下更復雜,但是功能更加強大。通常被用作菜單、列表等。
一、ListView基本用法
ListView的基本使用步驟:
1、定義ListVIew佈局
2、創建ArrayAdapter對象
3、將ArrayAdapter對象和ListView綁定
新建項目ListViewTest,一切默認,編輯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="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
程序的目標是將水果名稱顯示到ListView控件上。編輯MainActivity.javapackage com.my.listviewtest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class MainActivity extends AppCompatActivity {
//定義數組,ListView上將要顯示的水果名稱
private String[] data = {"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple",
"Strawberry","Cherry","Mango","Apple","Banana","Orange","Watermelon","Pear","Grape",
"Pineapple", "Strawberry","Cherry","Mango"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView)findViewById(R.id.list_view);
//創建適配器
ArrayAdapter<String> adapter = new ArrayAdapter<>(MainActivity.this,
android.R.layout.simple_list_item_1,data);
//將適配器與ListView綁定
listView.setAdapter(adapter);
}
}
運行程序,結果如下:
可以實現上下滑動,顯示更多數據。
二、自定義ListView
很多時候ListView要顯示的項目並不單單是一條String數據,它還可以添加圖片、按鈕等控件來豐富顯示的內容。接下來將上面的程序修改,爲每一種水果提供一個顯示的圖片。
圖片資源下載地址:https://pan.baidu.com/s/1jJia3w6
將圖片複製到drawable目錄下。
實現自定義的ListView需要有2個前提準備。
1、創建自定義的ListView的子項(item)顯示的佈局。
2、爲item創建實體類,包括getter方法。
3、創建自定義的適配器。即繼承ArrayAdapter。並指定泛型爲剛剛創建的實體類類型。
接下來的步驟就和上述使用ListView的方法一樣了。即創建自定義的適配器對象後,將適配器與ListView進行綁定。
爲定製的ListView的item創建佈局fruit_item.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">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<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>
爲item創建實體類,新建Fruit類。
package com.my.listviewtest;
public class Fruit{
private String name; //水果名
private int imageId; //資源ID
public Fruit(String name,int imageId){
this.name = name;
this.imageId = imageId;
}
public String getName() {
return name;
}
public int getImageId() {
return imageId;
}
}
創建自定義的適配器。
package com.my.listviewtest;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
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; //資源ID
public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects){
super(context,textViewResourceId,objects);
resourceId = textViewResourceId;
}
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
//獲取當前item的Fruit實例
Fruit fruit = getItem(position);
//爲子項傳入佈局
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
ImageView fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
TextView fruitName = (TextView)view.findViewById(R.id.fruit_name);
//設置顯示的內容
fruitImage.setImageResource(fruit.getImageId());
fruitName.setText(fruit.getName());
return view;
}
}
在自定義ListView的過程中,自定義的適配器非常重要,上述代碼中,我們先重寫了父類的一個構造方法,將上下文、ListView的子項佈局和數據傳遞進來。然後重寫了getView()方法,這個方法在每一個子項滾動到屏幕中的時候都會被調用,我們重寫的getView()方法包含三步,第一步,獲取當前項的Fruit實例,第二步,爲子項傳入佈局,注意寫法。第三步,設置要顯示的內容。最後將view返回。這個自定義的適配器的創建過程一定要理解。最後,修改MainActivity中的代碼。
package com.my.listviewtest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
//定義數組,ListView上將要顯示的水果名稱
// private String[] data = {"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple",
// "Strawberry","Cherry","Mango","Apple","Banana","Orange","Watermelon","Pear","Grape",
// "Pineapple", "Strawberry","Cherry","Mango"};
//使用List裝載將要顯示的數據
private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView)findViewById(R.id.list_view);
//初始化水果數據
initFruits();
//創建自定義適配器對象
FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
//創建適配器
// ArrayAdapter<String> adapter = new ArrayAdapter<>(MainActivity.this,
// android.R.layout.simple_list_item_1,data);
//將適配器與ListView綁定
listView.setAdapter(adapter);
}
//初始化水果數據,將水果數據裝到List中
private void initFruits() {
for(int i = 0;i < 2;i++){
Fruit apple = new Fruit("Apple",R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana = new Fruit("Banana",R.drawable.banana_pic);
fruitList.add(banana);
Fruit orange = new Fruit("Orange",R.drawable.orange_pic);
fruitList.add(orange);
Fruit watermelon = new Fruit("Watermelon",R.drawable.watermelon_pic);
fruitList.add(watermelon);
Fruit pear = new Fruit("Pear",R.drawable.pear_pic);
fruitList.add(pear);
Fruit grape = new Fruit("Grape",R.drawable.grape_pic);
fruitList.add(grape);
Fruit pineapple = new Fruit("Pineapple",R.drawable.pineapple_pic);
fruitList.add(pineapple);
Fruit strawberry = new Fruit("Strawberry",R.drawable.strawberry_pic);
fruitList.add(strawberry);
Fruit cherry = new Fruit("Cherry",R.drawable.cherry_pic);
fruitList.add(cherry);
Fruit mango = new Fruit("Mango",R.drawable.mango_pic);
fruitList.add(mango);
}
}
}
運行程序,結果如下;
三、提升ListView運行效率
上述代碼中,由於getView()方法每次都將佈局重新加載、每次都要獲取ImageView、TextView控件實例,導致ListView在快速滾動時的性能表現會非常差。我們可以利用getView()方法中的convertView參數將之前加載好的佈局進行緩存。爲了不讓getView()方法每次運行都去獲取控件實例,藉助ViewHolder就可以進行優化。
修改FruitAdapter的代碼:
...
public class FruitAdapter extends ArrayAdapter<Fruit> {
...
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
//獲取當前item的Fruit實例
Fruit fruit = getItem(position);
// //爲子項傳入佈局
// View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
//
// ImageView fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
// TextView fruitName = (TextView)view.findViewById(R.id.fruit_name);
//
// //設置顯示的內容
// fruitImage.setImageResource(fruit.getImageId());
// fruitName.setText(fruit.getName());
View view;
ViewHolder viewHolder;
if(convertView == null){ //緩存爲空
//加載佈局
view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
//只有在緩存爲空的情況下,纔會創建ViewHolder實例
viewHolder = new ViewHolder();
//關聯控件
viewHolder.fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
viewHolder.fruitName = (TextView)view.findViewById(R.id.fruit_name);
//將ViewHolder存儲到view中
view.setTag(viewHolder);
}else{ //緩存不爲空
view = convertView;
//重新獲取ViewHolder
viewHolder = (ViewHolder)view.getTag();
}
//設置顯示內容
viewHolder.fruitImage.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());
return view;
}
//內部類ViewHolder
class ViewHolder{
ImageView fruitImage;
TextView fruitName;
}
}
瞭解以上代碼需要明確兩點:
1、convertView緩存的是佈局。
2、ViewHolder的目的是避免每次調用getView()方法時都去獲取控件實例。
四、點擊事件
ListView不光只是展示數據,它的每個子項都可以對應一個點擊事件。
例如實現上述項目的子項點擊事件,每次點擊都彈出Toast提示,告訴用戶點擊的是哪一種水果。
修改MainActivity的代碼,添加點擊事件:
...
public class MainActivity extends AppCompatActivity {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
//將適配器與ListView綁定
listView.setAdapter(adapter);
//點擊事件,Toast提示,彈出水果名稱
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();
}
});
}
...
}
運行程序,點擊子項,結果如下:
ListView會經常被使用到,所以熟練掌握ListView的基本用法和自定義ListView的方法非常重要。
本文總結參考自郭神(郭霖)的《第一行代碼 第2版》