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

在学习了 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 {@Overridepublic int getCount() {return 0;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic 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;}@Overridepublic int getCount() {return mName.length;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic 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};@Overrideprotected 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() {@Overridepublic 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.hqwc.cn/news/619713.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ROS2从入门到精通1-3:详解ROS2动作通信机制与自定义动作

目录 0 专栏介绍1 动作通信模型2 动作模型实现(C)3 动作模型实现(Python)4 自定义动作 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌握ROS2底层基本分布式原理&#xff0c;并具有机器人建模和应用ROS2进行实际项目的开发和调试的工程能力。 &#x1f680;详情&a…

【Linux深造日志】运维工程师必会Linux常见命令以及周边知识!

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位宝子们好啊&#xff01;我是博主鸽芷咕。日志这个东西我相信大家都不陌生&#xff0c;在 linxu/Windows 系统…

暖宝轻工机械有限公司现已加入2024第13届生物发酵展

参展企业介绍 公司坐落于富饶的长江三角洲&#xff0c;美丽的瓯越山水---温州&#xff0c;成立20多年来&#xff0c;专业从事换热器新品研发、应用设计、生产制造、销售服务为一体的综合性生产企业。 公司致力于食品、饮料、果酒、制药、暖通、化工等行业领域的加热冷却、蒸发…

微信定时发送指定消息

微信定时发送消息 简介&#xff1a; 该项目为微信定时发送消息机器人&#xff0c;可以扫码登录微信&#xff0c;输入微信好友名称或群聊名称&#xff0c;添加定时任务内容&#xff08;时间、内容、图片&#xff09;&#xff0c;便可在指定时间发送该设置好的内容。 该项目包…

爬虫的目的是做什么

通过网站域名获取HTML数据解析数据&#xff0c;获取想要的信息存储爬取的信息如果有必要&#xff0c;移动到另一个网页重复过程 这本书上的代码的网址是 &#xff1a; GitHub - REMitchell/python-scraping: Code samples from the book Web Scraping with Python http://shop.…

51单片机-独立按键模块

1. 独立按键控制LED状态 轻触按键实现原理&#xff1a;按下时&#xff0c;接通&#xff0c;通过金属弹片受力弹动来实现接通和断开。 松开按键 按下之后&#xff1a;就会被连接 同时按下K1和K2时&#xff0c;P2_0,接口所连LED灯才亮。 #include <REGX52.H> void ma…

linux学习:目录检索

目录 目录 api 例子 目录 Linux 中的目录并不是一种容器&#xff0c;而仅仅是一个文件索引表 Linux 中目录就是一组由文件名和索引号组成的索引表&#xff0c;目录下的文件的真正内容存储 在分区中的数据域区域。目录中索引表的每一项被称为“目录项”&#xff0c;里面至少…

力扣HOT100 - 240. 搜索二维矩阵 II

解题思路&#xff1a; 从左下角开始&#xff0c;根据条件删除行和列。 class Solution {public boolean searchMatrix(int[][] matrix, int target) {int row matrix.length - 1;int col matrix[0].length - 1;int l 0;while (row > 0 && l < col) {if (targ…

MR鼻祖呼吁不要滥用孟德尔随机化法,多数文章没有意义

孟德尔随机化,Mendilian Randomization&#xff0c;简写为MR&#xff0c;是一种在流行病学领域应用广泛的一种实验设计方法&#xff0c;利用公开数据库就能轻装上阵写文章&#xff0c;甚至是高质量的论文。 近几年绝对是发文利器呀&#xff01; 但&#xff0c;最近MR鼻祖&#…

MBTI入侵职场,题目都用大模型生成了?!

宝子们&#xff0c;MBTI测过吗&#xff1f; 什么是MBTI呢&#xff1f;它是一个深入抽丝剥茧的性格测试&#xff0c;它的全称是Myers-Briggs Type Indicator&#xff08;迈尔斯-布里格斯性格指标&#xff09;&#xff0c;它会从四个维度上分析你的行为、喜好和思考方式&#xf…

Eigen库从入门到放弃(2. Getting Started)

Eigen的头文件定义了多种类型&#xff0c;但是对于简单的来说&#xff0c;使用MatrixXd就足够了&#xff0c;MatrixXd表示任意尺寸的矩阵&#xff0c;但是要注意数据类型是double的。Eigen/Dense的头文件定义了所有MatrixXd和相关类型的成员函数。所有头文件中定义的函数都是在…

【论文阅读——SplitFed: When Federated Learning Meets Split Learning】

级别CCFA 1.摘要 联邦学习&#xff08;FL&#xff09;和分割学习&#xff08;SL&#xff09;是两种流行的分布式机器学习方法。两者都采用了模型对数据的场景&#xff1b;客户端在不共享原始数据的情况下训练和测试机器学习模型。由于机器学习模型的架构在客户端和服务器之间…