25. 【Android教程】列表控件 ListView

news2025/3/6 3:02:40

在学习了 ScrollView 及 Adapter 两节内容之后,大家应该对 ListView 有了一些基本的了解,它是一个列表样式的 ViewGroup,将若干 item 按行排列。ListView 是一个很基本的控件也是 Android 中最重要的控件之一。它可以帮助我们完成多个 View 的垂直排列并支持滚动显示效果,而它比 ScrollView 更灵活也更易扩展,Adapter 作为 UI 控件和数据源之间的桥梁,会帮我们实现 MVC 模式,所以在实际开发中大多数的列表场景我们会优先考虑使用 ListView 来实现(目前 Google 推出了新的更强大的列表控件——RecyclerView,不过基本原理和 ListView 类似)。

1. ListView 的特性

ListView 在 Android App 中无处不在,比如最常用的“联系人”就可以通过 ListView 轻松实现。通过 ListView 用户可以上下滑动来浏览列表信息,我们可以在 ListView 中放置各种控件,比如 ImageView、Button、ToggleButton 等来丰富我们的列表样式。

正因为 ListView 通常是用来展示大量的数据集的控件,所以我们不可能挨个的为每个 item 去设置相应的数据,这时候就要借助 Adapter 来帮助我们完成 UI 控件和数据的绑定工作了。

2. ListView 的基本用法

ListView 相比其他控件来讲确实比较特殊,也有很多使用技巧,但是它作为一个 ViewGroup,同样也有自己的布局属性、 API 及事件监听器。

2.1 ListView 的常用属性

  • divider:
    设置 item 之间的分隔线,可以设置成颜色,也可以设置成 drawable 资源。
  • dividerHeight:
    设置分隔线的高度;
  • footerDividersEnabled:
    是否在 footerView(表尾)前绘制一个分隔线,默认为 true;
  • headerDividersEnabled:
    是否在 headerView(表首)前绘制一个分隔线,默认为 true;
  • android:scrollbars:
    设置滚动条样式,有两种样式: horizontal 和 vertical,以及 none 表示隐藏滚动条。

2.2 ListView 的常用 API

  • addHeaderView(View v):
    添加 headView,headView 会固定显示在表的第一个元素之前。参数是一个 View 对象,比如可以用作“下拉刷新”的 View;
  • addFooterView(View v):
    添加 footerView,footerView 会固定显示在表的最后一个元素之后。参数是一个 View 对象,比如可以用作“上拉加载更多”的 View;
  • addHeaderView(View v, Object data, boolean isSelectable):
    添加 headView,第二个参数表示与 headView 绑定的数据对象,第三个参数表示当前这条 item 是否可选中,通常“下拉刷新”可以设置成无法选中;
  • addFooterView(View v, Object data, boolean isSelectable):
    添加 footerView,第二个参数表示与 footerView 绑定的数据对象,第三个参数表示当前这条 item 是否可选中,通常“上拉加载更多”可设置成无法选中。

2.3 点击事件监听器

ListView 的样式示意图如下:

ListView 中的每个 item 可以设置成任意样式,可以包含任意的 Android 控件,非常灵活。接下来,我们来一起看看如何使用。

3. ListView 的使用示例

使用 ListView 就一定逃不开 Adapter,在上一节我们介绍了 ArrayAdapter 和 SimpleAdapter 配合 ListView 的使用方法,其实 ArrayAdapter 和 SimpleAdapter 都是继承 BaseAdapter 做的封装,那么这一节我们就来看看 BaseAdapter 究竟是何方神圣。为了让大家更好的看到对比,这一节我们用 BaseAdapter 来实现上一节的水果的列表。

3.1 自定义 Adapter

BaseAdapter 是一个接口,我们自定义 Adapter 就需要实现一个 BaseAdapter 接口,首先创建一个 MyAdapter 类实现 BaseAdapter 接口,如下:

package com.emercy.myapplication;

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public class MyAdapter extends BaseAdapter {
    @Override
    public int getCount() {
        return 0;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return null;
    }
}

可以看到,继承自 BaseAdapter 的类有 4 个方法是必须实现的,我们具体看看这四个方法分别表示什么以及如何实现:

  • public int getCount():
    返回列表的长度,即 ListView 需要展示的 item 数量。通常我们会将数据保存在 List 或者数组当中,从而可以通过数据或者 list 获取列表的长度返回即可。比如如果我们通过 ArrayList 保存列表的数据,那么我们可以通过 List 的 size() 方法获取列表的长度,并在 getCount() 回调方法中返回,如下:
    @Override
    public int getCount() {
      int count = arrayList.size();     // 计算数据 ArrayList 的长度
      return count;                     // 返回列表的长度
    }
    
  • public Object getItem(int position):
    获取位于 position 的 item 对应的数据内容,当 ListView 需要填充第 position 个 item 的时候会回调此函数获取当前 item 上应该显示的数据内容,如果数据存在 ArrayList 当中,直接返回当前 position 的 ArrayList 内容即可,如下:
    @Override
    public Object getItem(int i):
      return arrayList.get(i);        // item 对应的数据内容
    }
    
  • public long getItemId(int position) :
    返回当前行的 itemid,itemid 是唯一标识当前 item 的索引,通常情况下我们可以直接返回 position,如下:
    @Override
    public long getItemId(int i) {
      return i;
    }
    
  • public View getView(int position, View convertView, ViewGroup parent):
    当列表中的一个 item 即将被展示的时候系统会回调此函数,我们需要在此回调接口中完成数据与 UI 控件的绑定。通过LayoutInflater类获取布局对象,然后通过findViewById拿到具体的控件,并将数据内容设置到控件当中,比如我们需要在列表中设置一个图片资源:
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
      view = inflter.inflate(R.layout.activity_gridview, null);      // 获取布局对象
      ImageView icon = (ImageView) view.findViewById(R.id.icon);     // 通过ID拿到具体的View对象
      icon.setImageResource(flags[i]);                               // 设置ImageView的图片资源
      return view;
    }
    

3.2 编写布局文件

为了对比学习,本例实现一个和上一节中 SimpleAdapter 的水果列表相同的例子,布局文件可直接引用,具体代码可以参考 第 23 节第 2 小节的内容。

3.3 创建数据模型

在 Adapter 中创建我们需要保存的数据,和上一节的例子一样,我们用两个数组分别保存水果名称和水果图片资源:

String[] mDataName = {"苹果", "梨", "香蕉", "桃子", "西瓜", "荔枝", "橘子"};
int[] mDataImage = {R.drawable.apple, R.drawable.pear, R.drawable.banana, R.drawable.peach,
            R.drawable.watermelon, R.drawable.lychee, R.drawable.orange, R.drawable.orange};

在 MyAdapter 中新增数据更新接口,用于初始数据的设置及后续数据的更新:
MyAdapter.java

public void setData(String[] name, int[] resId)

这样一来我们就有了数据源,接着按照 第 24 节 3.1 小节中对 4 个回调接口的描述修改回调方法体。主要是在getCount中返回数组长度,getView中通过 layout 对象获取到 TextView 和 ImageView,然后设置水果名称和图片,最终 MyAdapter 类的代码如下:

package com.emercy.myapplication;

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;


public class MyAdapter extends BaseAdapter {

    private Context mContext;
    private String[] mName;
    private int[] mResId;

    public MyAdapter(Context context) {
        mContext = context;
    }

    public void setData(String[] name, int[] resId) {
        mName = name;
        mResId = resId;
    }


    @Override
    public int getCount() {
        return mName.length;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        convertView = LayoutInflater.from(mContext).inflate(R.layout.list_view, null);
        TextView name = convertView.findViewById(R.id.textView);
        ImageView image = convertView.findViewById(R.id.imageView);
        name.setText(mName[position]);
        image.setImageResource(mResId[position]);
        return convertView;
    }
}

3.4 编写主 Activity

ListView 的核心适配逻辑都在 Adapter 中完成,主 Activity 比较简单,主要做以下几件事:

  • 获取 listView 对象
  • 创建自定义 adapter,即 MyAdapter,并设置数据
  • 将自定义 Adapter 设置给 ListView
  • 设置 ListView 列表项的点击事件
    代码如下:
package com.emercy.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {

    ListView mListView;
    String[] mDataName = {"苹果", "梨", "香蕉", "桃子", "西瓜", "荔枝", "橘子"};
    int[] mDataImage = {R.drawable.apple, R.drawable.pear, R.drawable.banana, R.drawable.peach,
            R.drawable.watermelon, R.drawable.lychee, R.drawable.orange, R.drawable.orange};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mListView = findViewById(R.id.listView);

        MyAdapter adapter = new MyAdapter(this);
        adapter.setData(mDataName, mDataImage);
        mListView.setAdapter(adapter);

        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Toast.makeText(getApplicationContext(), mDataName[i], Toast.LENGTH_LONG).show();
            }
        });
    }
}

运行效果和上一节一样:

4. 小结

本节主要介绍了 ListView 搭配 BaseAdapter 实现列表功能的方法,BaseAdapter 比 ArrayAdapter 和 SimpleAdapter 拥有更大的可控性,我们可以自己实现很多复杂的功能。目前更推荐使用的是 Google 近年推出的 RecyclerView,不过基本原理和 ListView 类似,本节主要介绍的是基础的用法,在掌握了基本用法及核心思想之后,可以继续学习一些优化手段及高级用法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1599757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里云优惠券种类介绍及领取教程详解

随着互联网技术的快速发展&#xff0c;越来越多的企业和个人开始将业务和数据迁移到云端。阿里云作为国内领先的云服务提供商&#xff0c;为广大用户提供了丰富多样的云产品和服务。为了回馈用户&#xff0c;阿里云经常推出各种优惠活动&#xff0c;其中优惠券就是其中一种常见…

如何研究解决问题

如何研究解决问题 目录概述需求&#xff1a; 设计思路实现思路分析1.如何研究解决问题寻找解决方案如何借鉴过往经验 范例1.过程2.寻求的专家意见 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0…

ctf.show_web13

上传一句话木马 1.php文件&#xff0c;显示 再改后缀为.jpg&#xff0c;显示错误文件大小 用dirsearch扫一下 备份文件.bak 下载文件源码 <?php header("content-type:text/html;charsetutf-8");$filename $_FILES[file][name];$temp_name $_FILES[file][tm…

新版AndroidStudio使用switch-case语句时出现Constant expression required错误

原因: 在新版的Android Studio中使用JDK17以上版本&#xff0c;会出现switch语句报错"Constant expression required"的问题&#xff0c;这是因为在JDK17中switch语句的条件表达式支持使用枚举类型&#xff0c;而这个特性还没有被支持。 解决方法: ①在gradle.prope…

java二维数组

一、二维数组的概述&#xff1a; 目录 二维数组的概述&#xff1a; 二维数组图解&#xff1a; 二维数组的四种创建方式&#xff1a; Java 用sort对二维数组进行排序 二维数组简单概述&#xff1a;Java中的二维数组一般应用在矩阵的一些运算、棋盘游戏中棋盘的实现、二维数据…

使用阿里云试用Elasticsearch学习:5. 地理位置

我们拿着纸质地图漫步城市的日子一去不返了。得益于智能手机&#xff0c;我们现在总是可以知道 自己所处的准确位置&#xff0c;也预料到网站会使用这些信息。我想知道从当前位置步行 5 分钟内可到的那些餐馆&#xff0c;对伦敦更大范围内的其他餐馆并不感兴趣。 但地理位置功…

【Linux】磁盘阵列RAID技术

目录 一、RAID介绍 1.1 什么是RAID技术&#xff1f; 1.2 为什么要使用RAID技术&#xff1f; 二、RAID级别 2.1 常见的RAID级别 2.2 常见RAID介绍 三、RAID特性对比 一、RAID介绍 1.1 什么是RAID技术&#xff1f; 把多块独立的物理磁盘按不同的方式组合起来形成一个硬盘…

基于zookeeper安装Kafka集群

操作系统&#xff1a;centOS 9 Stream&#xff0c;6台&#xff0c;基于vmware虚拟机创建 准备工作 确认系统环境&#xff1a; 确保所有服务器已安装了最新更新。安装Java Development Kit (JDK) 8或更高版本&#xff0c;因为ZooKeeper和Kafka都是基于Java开发的。例如&#x…

【安全】查杀linux挖矿病毒 kswapd0

中毒现象 高cpu占用&#xff0c;使用top命令查看cpu使用率长时间50%以上&#xff0c;cpu占用异常的进程八成就是挖矿病毒进程 此病毒隐藏了自己&#xff0c;top命令无法查看到挖矿病毒进程&#xff0c;可通过sysdig命令找到隐藏进程 安装sysdig curl -s https://s3.amazonaw…

外卖小程序实战-接单后小票机自动打印订单

1、导入小票机的sdk https://www.feieyun.com/api/API-JAVA.zip public static String addprinter(String snlist){//通过POST请求&#xff0c;发送打印信息到服务器RequestConfig requestConfig RequestConfig.custom() .setSocketTimeout(30000)//读取超时 .setConnectTi…

文件读写异常处理(day25)

题目一&#xff1a;文件读写异常处理 要求&#xff1a; 编写一个Java程序&#xff0c;该程序尝试读取一个名为example.txt的文件&#xff0c;并逐行打印其内容到控制台。 如果文件example.txt不存在&#xff0c;程序应捕获FileNotFoundException异常&#xff0c;并输出相应的…

ActiveMQ 任意文件上传漏洞复现

一、使用弱口令登陆 ​ 访问 http://ip:8161/admin/ 进入admin登陆页面&#xff0c;使用弱口令登陆&#xff0c;账号密码皆为 admin&#xff0c;登陆成功后&#xff0c;headers中会出现验证信息 ​ 如&#xff1a; Authorization: Basic YWRtaW46YWRtaW4 # 二、利用PUT协议上…

Docker 入门介绍及简单使用

Docker 的简单介绍 中文官网&#xff1a;Docker中文网 官网 英文官网&#xff1a;Docker: Accelerated Container Application Development Docker 是一个开源的应用容器引擎&#xff0c;它允许开发者打包应用及其依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 …

【Java开发指南 | 第八篇】Java变量、构造方法、创建对象

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 Java变量构造方法创建对象 Java变量 在Java中&#xff0c;变量用于存储数据值。它们是程序中用于保存信息的一种基本方式。变量在程序执行过程中可以被赋予不同的值&#xff0c;并且这些值可以在程序的不同部分…

使用Python模仿文件行为

在Python中&#xff0c;你可以通过文件操作函数&#xff08;如open()函数&#xff09;以及模拟输入输出流的库&#xff08;如io模块&#xff09;来模拟文件行为。下面是一些示例&#xff0c;展示了如何使用这些工具在Python中模拟文件行为。 1、问题背景 在编写一个脚本时&…

轮胎行业EDI:Tigar 轮胎EDI项目案例

Tigar 轮胎是一家塞尔维亚轮胎制造公司&#xff0c;自2007年开始&#xff0c;被轮胎制造商米其林持有。 Tigar通过EDI来传输与供应商之间的业务单据&#xff0c;优化业务流程。本文将从EDI需求概览、如何基于知行之桥EDI系统实现与Tigar的EDI对接以及项目回顾这三个部分为大家展…

Docker部署MongoDB数据库

文章目录 官网地址docker 网络部署 MongoDB部署 mongo-expressdocker-compose.ymlMongoDB shell 官网地址 https://www.mongodb.com/zh-cn docker 网络 # 创建 mongo_network 网络 docker network create mongo_network # 查看网络 docker network list # 容器连接到 mongo_…

AI智能分析网关V4平台告警数据清理方法:自动清理与手动清理

TSINGSEE青犀智能分析网关V4属于高性能、低功耗的软硬一体AI边缘计算硬件设备&#xff0c;目前拥有3种型号&#xff08;8路/16路/32路&#xff09;&#xff0c;支持Caffe/DarkNet/TensorFlow/PyTorch/MXNet/ONNX/PaddlePaddle等主流深度学习框架。硬件内部署了近40种AI算法模型…

C语言中的结构体:从定义到传递

前言 结构体是C语言中一种重要的数据类型&#xff0c;它允许我们将不同类型的数据组合成一个整体&#xff0c;并以自定义的方式进行操作。通过结构体&#xff0c;我们可以更加灵活地管理和处理复杂的数据结构&#xff0c;从而提高程序的可读性和可维护性。本篇博客将从结构体的…

allure2教程-1-环境搭建

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 自动化测试执行完成后我们需要展示给其他人看&#xff0c;这就要有自动化测试报告了。复杂的测试报告当然可以自己代码实现&#xff0c;但用pytest-html或allure基本也能满足我们生成测试报告的要求了。本小节介绍…