文章目录
- 1 自定义ListView列表项
- 1.1 自定义布局文件
- 1.2 自定义Adapter加载自定义布局
- 2 进行ListView进行适配
- 2.1 自定义JavaBean
- 2.2 自定义布局与ListIView绑定
- 2.2.1 主布局文件
- 2.2.2 获取自定义布局文件,填充主布局文件
- 3 对自定义布局的加载进行优化
- 3.1 对自定义列表适配器进行优化
- 3.2 完整优化代码
- 4 结果
1 自定义ListView列表项
- LIstView支持自定义列表项,此时需要自定义布局文件
- 在自定义布局文件需要使用类型数据的时候,此时需要自定义适配器
1.1 自定义布局文件
- 新建layout.xml文件
- 新建的layout布局是列表项的布局,相当于在列表项中进行自定义布局
<?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="wrap_content">
<ImageView
android:layout_width="100dp"
android:layout_height="80dp"
android:id="@+id/fruit_image"
android:src="@drawable/apple"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fruit_name"
android:text="name"
android:textSize="30sp"
android:textColor="#000000"
android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fruit_price"
android:text="name"
android:textSize="30sp"
android:textColor="#ff0000"
android:layout_gravity="center_vertical"
android:layout_marginLeft="40dp"
/>
</LinearLayout>
1.2 自定义Adapter加载自定义布局
- 自定义Adapter需要继承一个父类适配器,例如:ArrayAdapter, 并覆盖其中的构造方法与**getView()**方法
- 自定义构造方法:必须是有参构造方法
- 参数一:上下文环境,例如MainActivity.this
- 参数二:布局文件的ID,为R.layout.layout
- 参数三:为列表类型的数据源
// 参数1 为上下文, 参数2 为layout布局的id, 参数3 为数据源
public FruitAdapter(@NonNull Context context, int resource, @NonNull List<Fruit> objects) {
super(context, resource, objects);
}
- getView方法,填充自定义布局
使用步骤:
- 获取传入数组的数据项,数组或者列表在构造方法中传入
- 将自定义布局转化为View类型,使用 **inflate()**方法进行填充
LayoutInflater.from(getContext()).inflate(R.layout.fruit_layout, parent, false);
- 在view中获取其中的控件,填充其中的信息
- 最后返回布局view
// 屏幕滑动的时候,调用子项
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
//1. 得到当前fruit实例, 可见 fruit在适配器中
Fruit fruit = getItem(position);
// 2. 为子项加载布局, 传入到ViewGroup中
View view = LayoutInflater.from(getContext()).inflate(R.layout.fruit_layout, parent, false);
// 3. 获取View中的控件,并为控件赋值
ImageView fruitImage = view.findViewById(R.id.fruit_image);
TextView fruitName = view.findViewById(R.id.fruit_name);
TextView fruitPrice = view.findViewById(R.id.fruit_price);
// 4. 设置图片以及文件资源
fruitImage.setImageResource(fruit.getImageID());
fruitName.setText(fruit.getName());
fruitPrice.setText("$" + fruit.getPrice() / 100 + "/KG");
// 5. 返回设置好的布局
return view;
}
2 进行ListView进行适配
2.1 自定义JavaBean
package com.hlq.sz_ch_listviewdemo02;
public class Fruit {
private int imageID;
private String name;
private long price;
public void setImageID(int imageID) {
this.imageID = imageID;
}
public void setName(String name) {
this.name = name;
}
public void setPrice(long price) {
this.price = price;
}
public int getImageID() {
return imageID;
}
public String getName() {
return name;
}
public long getPrice() {
return price;
}
public Fruit(int imageID, String name, long price) {
this.imageID = imageID;
this.name = name;
this.price = price;
}
public Fruit() {
}
}
2.2 自定义布局与ListIView绑定
2.2.1 主布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
2.2.2 获取自定义布局文件,填充主布局文件
- 在内存中新建自定义列表适配器,
new FruitAdapterEnhance(MainActivity.this, R.layout.fruit_layout, fruits);
- 绑定适配器,
listView.setAdapter(fruitAdapter);
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
// 内部对象
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1. 绑定控件
listView = (ListView)findViewById(R.id.list_view);
// 2. 准备数据
List<Fruit> fruits = new ArrayList<>();
for (int i = 0; i < 2; ++i) {
Fruit pineApple = new Fruit(R.drawable.pineapple, "菠萝", 1690);
fruits.add(pineApple);
Fruit mango = new Fruit(R.drawable.mango, "芒果", 2990);
fruits.add(mango);
Fruit grape = new Fruit(R.drawable.grape, "葡萄", 1990);
fruits.add(grape);
Fruit pomegranate = new Fruit(R.drawable.pomegranate, "石榴", 1500);
fruits.add(pomegranate);
Fruit apple = new Fruit(R.drawable.apple, "苹果", 2000);
fruits.add(apple);
Fruit watermelon = new Fruit(R.drawable.watermelon, "西瓜", 2880);
fruits.add(watermelon);
Fruit orange = new Fruit(R.drawable.orange, "橘子", 1880);
fruits.add(orange);
}
// 3. 设置子布局
// 4. 定义适配器, 控件与数据的桥梁
FruitAdapterEnhance fruitAdapter = new FruitAdapterEnhance(MainActivity.this, R.layout.fruit_layout, fruits);
listView.setAdapter(fruitAdapter);
// 5. 设置点击事件
// 4 为列表适配器增加响应事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view, int position , long i) {
// 从View中获取信息, 此时的View为点击的View
TextView textView = view.findViewById(R.id.fruit_name);
String result = textView.getText().toString();
Toast.makeText(MainActivity.this, "选择的选项为: " + result, Toast.LENGTH_SHORT).show();
// 上下文必须指定为MainActivity.this
}
});
}
}
3 对自定义布局的加载进行优化
- 优化思想:在用户进行滑动的时候,每一个列表项都需要重新加载,由于布局要加载到内存,造成ListView的性能下降
- 为了优化性能,可以将ListView的布局保存,不必重新加载,每一个列表项只是将数据填入到布局中
3.1 对自定义列表适配器进行优化
- 自定义内部类,包含列表项中的布局控件,此时为ViewHolder
- 第一次加载时,View的引用为null, 将ViewHolder内部类存储在view中,使用
view.setTag(viewHolder);
- 当view的引用不为null的时候,获取view布局,并获取其中的内部类进行布局的填充
view = convertView; viewHolder = (ViewHolder)view.getTag();
- 每一个项目的加载都需要设置信息,因此在ViewHolder内部类中填充信息。获取View控件,进行资源的设置,例如:
viewHolder.getFruitImage().setImageResource(fruit.getImageID());
viewHolder.getFruitName().setText(fruit.getName());
3.2 完整优化代码
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 androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.List;
public class FruitAdapterEnhance extends ArrayAdapter<Fruit> {
// 构造函数
// 参数1 为上下文, 参数2 为layout布局的id, 参数3 为数据源
public FruitAdapterEnhance(@NonNull Context context, int resource, @NonNull List<Fruit> objects) {
super(context, resource, objects);
}
// 屏幕滑动的时候,调用子项
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
//1. 得到当前fruit实例, 从适配的位置获取 使得控件与数据项一一对应
Fruit fruit = getItem(position);
// 1. 新增ViewHolder
ViewHolder viewHolder;
View view;
// 2. 是否加载了布局
if (convertView == null) {
// 2.1 没有加载布局的时候,使用子布局
view = LayoutInflater.from(getContext()).inflate(R.layout.fruit_layout, parent, false);
viewHolder = new ViewHolder();
viewHolder.setFruitImage(view.findViewById(R.id.fruit_image));
viewHolder.setFruitName(view.findViewById(R.id.fruit_name));
viewHolder.setFruitPrice(view.findViewById(R.id.fruit_price));
// 2.2 将viewHolder存储与view中
view.setTag(viewHolder);
} else {
// 从新获取viewHolder
view = convertView;
viewHolder = (ViewHolder)view.getTag();
}
// 3. 设置viewGroup中的内容
viewHolder.getFruitImage().setImageResource(fruit.getImageID());
viewHolder.getFruitName().setText(fruit.getName());
viewHolder.getFruitPrice().setText("$" + fruit.getPrice() / 100 + "/Kg");
// // 2. 为子项加载布局, 传入到ViewGroup中
// View view = LayoutInflater.from(getContext()).inflate(R.layout.fruit_layout, parent, false);
//
// // 3. 获取View中的控件,并为控件赋值
// ImageView fruitImage = view.findViewById(R.id.fruit_image);
// TextView fruitName = view.findViewById(R.id.fruit_name);
// TextView fruitPrice = view.findViewById(R.id.fruit_price);
//
// // 4. 设置图片以及文件资源
// fruitImage.setImageResource(fruit.getImageID());
// fruitName.setText(fruit.getName());
// fruitPrice.setText("$" + fruit.getPrice() / 100 + "/KG");
//
// // 5. 返回设置好的布局
return view;
}
// 3设置内部类,加载布局,只需提供数据,加快读取速度
private class ViewHolder{
ImageView fruitImage;
TextView fruitName;
TextView fruitPrice;
public ImageView getFruitImage() {
return fruitImage;
}
public TextView getFruitName() {
return fruitName;
}
public TextView getFruitPrice() {
return fruitPrice;
}
public void setFruitImage(ImageView fruitImage) {
this.fruitImage = fruitImage;
}
public void setFruitName(TextView fruitName) {
this.fruitName = fruitName;
}
public void setFruitPrice(TextView fruitPrice) {
this.fruitPrice = fruitPrice;
}
}
}