Andriod 自定义ListView的列表项

本文详细介绍了如何在Android中实现自定义ListView列表项,包括创建自定义布局文件、自定义Adapter以及优化加载性能。通过创建JavaBean、绑定布局与ListView并利用ViewHolder优化滑动性能,展示了完整的自定义ListView适配过程。
摘要由CSDN通过智能技术生成

1 自定义ListView列表项

  • LIstView支持自定义列表项,此时需要自定义布局文件
  • 在自定义布局文件需要使用类型数据的时候,此时需要自定义适配器

1.1 自定义布局文件

  1. 新建layout.xml文件
  2. 新建的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()**方法
  1. 自定义构造方法:必须是有参构造方法
  • 参数一:上下文环境,例如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);

    }

  1. getView方法,填充自定义布局

使用步骤:

  1. 获取传入数组的数据项,数组或者列表在构造方法中传入
  2. 将自定义布局转化为View类型,使用 **inflate()**方法进行填充 LayoutInflater.from(getContext()).inflate(R.layout.fruit_layout, parent, false);
  3. 在view中获取其中的控件,填充其中的信息
  4. 最后返回布局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 对自定义列表适配器进行优化

  1. 自定义内部类,包含列表项中的布局控件,此时为ViewHolder
  2. 第一次加载时,View的引用为null, 将ViewHolder内部类存储view中,使用view.setTag(viewHolder);
  3. 当view的引用不为null的时候,获取view布局,并获取其中的内部类进行布局的填充view = convertView; viewHolder = (ViewHolder)view.getTag();
  4. 每一个项目的加载都需要设置信息,因此在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;
        }
    }

}

4 结果

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值