从0系统学Android--3.5 最常用和最难用的控件---ListView
从0系统学Android-- 3.5 最常用和最难用的控件---ListView
本系列文章目录:更多精品文章分类
本系列持续更新中....
3.5 最常用和最难用的控件---ListView
ListView 是我们在开发中最常使用的控件之一。由于手机屏幕空间比较有限,能够一次性在屏幕上显示的内容不多,ListView 允许用户可以通过手指上下滑动,可以呈现更多的数据。
3.5.1 ListView 的简单使用
首先还是在 Layout 中添加 ListView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
private String[] data = {
"Apple","fdsfs","fdsfssfs","wwww","wwwqqq","qqqqq","eeeee","rrrrrr","tttttt","yyyyyy","uuuuuu","aaaaaa","sssss"
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listviwe);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,data);
ListView listView = findViewById(R.id.lv);
listView.setAdapter(adapter);
}
ListView 是用于展示大量数据的,因此数据需要提供好,这些往往都是从网络上或者数据库读取的,这里就用假数据简单测试一下。
数据不能直接传递给 ListView 需要借助适配器来完成。Android 中提供了许多适配器的实现类。这里使用最简单的 ArrayAdapter
,android.R.layout.simple_list_itme_1
是 Android 内置的布局文件,里面只有一个简单的 TextView。然后使用 setAdapter
就将构建好的适配器对象传递进去,这样 Listview 和 数据之间的关联就建立了。
3.5.2 定制 LIstView 的界面
只显示一行文字太过单调了,下面对 ListView 的界面进行定制,显示更加复杂的内容。
定义一个实体类,作为 ListView 适配器的适配类型。新建 Fruit
类
public class Fruit {
private String name;
private int imgId;
public Fruit(String name,int imgId){
this.name = name;
this.imgId = imgId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getImgId() {
return imgId;
}
public void setImgId(int imgId) {
this.imgId = imgId;
}
}
其中 name
表示名字 imgId
对应图片的资源id。
下面为 ListView 的子项创建一个自定义的布局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="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/iv"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tv_name"
android:layout_marginLeft="10dp"/>
</LinearLayout>
下面自己建立适配器,这个适配器继承自 ArrayAdapter,并且制定泛型的类型是 Fruit
类型的。
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId;
public FruitAdapter(@NonNull Context context, int resource, @NonNull List<Fruit> objects) {
super(context, resource, objects);
resourceId = resource;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
// 获取当前项的 Fruit 实例
Fruit fruit = getItem(position);
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
TextView textView = view.findViewById(R.id.tv_name);
ImageView imageView = view.findViewById(R.id.iv);
// 这里没有图片,就偷懒使用了系统的
imageView.setImageResource(R.mipmap.ic_launcher);
textView.setText(fruit.getName());
return view;
}
}
FruitAdapter 继承 ArrayAdapter 比较简单,只需要重写一组构造方法和一个 getView()
方法就可以了,其他的方法 ArrayAdapter
都实现了。
getItem()
方法在每个子项被滚动到屏幕内的时候都会被调用。
这里使用了 LayoutInflater
来为这个子项加载我们传入的布局,LayoutInflater 的 inflate
方法需要传入三个参数,第一个参数就是要加载的布局,第二个参数就是这个布局要加入到这父布局中,第三个参数指定成 false 表示只让我们在父布局中声明的 layout 属性生效,其实就是为了测量一下这个生成的布局,但是不会将这个 View 添加到父布局中,因为一旦 View 有了父布局后,就不能再添加到 ListView 中了。现在不理解也没关系,记住这是标准写法就行了。
最后我们在 Activity
中将 ListView 与我们自己创建的适配器绑定就可以了。
// 进行数据加工
initData();
FruitAdapter fruitAdapter = new FruitAdapter(this,R.layout.fuit_item,list);
ListView listView = findViewById(R.id.lv);
listView.setAdapter(fruitAdapter);
3.5.3 提高 ListView 的运行效率
ListView 还有很多的细节点需要优化,不然运行效率很低。因为在 getView()
方法中每次都将布局重新加载了一遍,当 ListView 快速滚动的时候,性能就会出现问题。
其实在 getView()
方法中还有一个 converView
参数,这个参数就是用于将之前加载好的布局进行缓存的,以便之后可以进行重复使用。修改 FruitDapter
的代码
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Fruit fruit = getItem(position);
View view ;
if (convertView == null){
view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
}else {
view = convertView;
}
TextView textView = view.findViewById(R.id.tv_name);
ImageView imageView = view.findViewById(R.id.iv);
imageView.setImageResource(R.mipmap.ic_launcher);
textView.setText(fruit.getName());
return view;
}
这样我们就充分把缓存的 conventView 利用起来了。
不过目前还需要优化,虽然不会再去重复的加载布局了,但是每次 getView()
方法中还是会调用 View
的 findViewById()
方法来获取一次控件的实例。我们可以借助 ViewHolder
来对这部分进行性能的优化。修改代码
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
// 获取当前项的 Fruit 实例
Fruit fruit = getItem(position);
View view ;
ViewHolder viewHolder;
if (convertView == null){
view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
viewHolder = new ViewHolder();
viewHolder.iv = view.findViewById(R.id.iv);
viewHolder.tv = view.findViewById(R.id.tv_name);
view.setTag(viewHolder); // 将 ViewHolder 存储在 View 中
}else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.iv.setImageResource(R.mipmap.ic_launcher);
viewHolder.tv.setText(fruit.getName());
return view;
}
class ViewHolder{
ImageView iv;
TextView tv;
}
新增加一个 ViewHolder
内部类,用于对控件的实例进行缓存,当 convertView 为 null 的时候就创建一个 ViewHolder
并将它存放在 View 中。当convertView
不为 null 的时候将 ViewHolder
实例取出来。这样就没有必要每次都要通过 findViewById()
来获取控件实例了。
通过以上两步,ListView 就优化的非常不错了。
3.5.4 ListView 点击事件
给 ListView 设置点击事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// 通过 positon 我们就可以确定是点击的哪一个子项
}
});
从0系统学Android--3.5 最常用和最难用的控件---ListView的更多相关文章
- Android学习之基础知识五—ListView控件(最常用和最难用的控件)
ListView控件允许用户通过上下滑动来将屏幕外的数据拉到屏幕内,把屏幕内的数据拉到屏幕外. 一.ListView的简单用法第一步:先创建一个ListViewTest项目,在activity_mia ...
- 从0系统学Android-2.5更多隐式Intent用法
本系列文章,参考<第一行代码>,作为个人笔记 更多内容:更多精品文章分类 从0系统学Android-2.5更多隐式Intent用法 上一节中我们学习了通过隐式 Intent 来启动 Act ...
- 从0系统学Android--4.1探究碎片
从0系统学Android--4.1探究碎片 本系列文章目录:更多精品文章分类 本系列持续更新中.... 初级阶段内容参考<第一行代码> 第四章:手机平板要兼顾--探究碎片 平板电脑和手机最 ...
- 从0系统学Android--3.7 聊天界面编写
从0系统学Android--3.7 聊天界面编写 本系列文章目录:更多精品文章分类 本系列持续更新中.... 3.7 编写界面的最佳实践 前面学习了那么多 UI 开发的知识,下面来进行实践,做一个美观 ...
- 从0系统学Android--3.6 RecyclerView
从0系统学Android--更强大的滚动控件---RecyclerView 本系列文章目录:更多精品文章分类 本系列持续更新中.... 参考<第一行代码> 首先说明一点昨天发了一篇关于 L ...
- 从0系统学Android--3.2四种基本布局
从0系统学Android--3.2四种基本布局 本系列文章目录:更多精品文章分类 本系列持续更新中.... 3.3 系统控件不够用?创建自定义控件 上一节我们学习了 Android 中的一些常用的控件 ...
- 从0系统学Android--3.1编写UI界面
从0系统学Android--3.1编写UI界面 本系列文章目录:更多精品文章分类 本系列持续更新中.... 界面设计和功能开发同样重要,界面美观的应用程序不仅可以大大增加用户粘性,还能帮我们吸引到更多 ...
- 从0系统学Android--2.6 Activity 的最佳实践
从0系统学Android--2.6 Activity 的最佳实践 本系列文章目录:更多精品文章分类 本系列持续更新中.... 实践中的技巧 2.6.1 知晓当前是在哪个 Activity 这个其实很简 ...
- 从0系统学Android--5.2 发送广播
从0系统学Android--52 发送广播 本系列文章目录:更多精品文章分类 本系列持续更新中.... 初级阶段内容参考<第一行代码> 5.3 发送自定义广播 前面已经学习了如何接受广播了 ...
随机推荐
- mac os 搭建私有DNS 之 dnsmasq
- MAC OS 创建私有DNS 仓库 - 使用场景 实际工作中有一些私有的域名需要修改host才可以访问 例如:localhost.dev develop-test.dev - 安装方法 brew ...
- luogu P1168 中位数 |树状数组+二分
题目描述 给出一个长度为NN的非负整数序列A_i,对于所有1 ≤ k ≤ (N + 1) / 21≤k≤(N+1)/2,输出A_1, A_3, -, A_2k - 1的中位数.即前1,3,5,-个数的 ...
- 使用dva改造旧项目的数据流方案
前言 最近在给自己的脚手架项目转到TypeScript时,遇到了一些麻烦. 项目之前采用的是react + react-redux + redux-thunk + redux-actions +re ...
- BOM对象学习
location,history,screen <!DOCTYPE html> <html> <head> <meta charset="utf-8 ...
- 【CSS】271- RGB、HSL、Hex网页色彩,看完这篇全懂了
作者:CSS可乐 http://csscoke.com/2015/01/01/rgb-hsl-hex/ 网页使用到的色彩标示方法中,从古早时期大家都在用的16进位码(#000000).RGB色值标示. ...
- Java环境变量配置超详细教程
https://blog.csdn.net/Mxdon_on/article/details/89461365 概述 Java的环境配置并不是特别难,但是对刚上手的新手来说确实是一个大问题 首先下载j ...
- hdu 2586 How far away?(LCA模板题+离线tarjan算法)
How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- 《Java基础知识》Java接口和抽象类的区别
抽象类 抽象类必须用 abstract 修饰,子类必须实现抽象类中的抽象方法,如果有未实现的,那么子类也必须用 abstract 修饰.抽象类默认的权限修饰符为 public,可以定义为 public ...
- spyder错误合集
SyntaxError: invalid syntax是非法语句的意思,检查语法是否出现错误,漏写等 SyntaxError: (unicode error) 'unicodeescape' co ...
- 955 不加班的公司名单:955.WLB
前两天说到,韩老师的 Github 总 star 数量超过了 20000!全球排名第 232! 他,TypeScript GitHub Star 上海第一,全国第四!GitHub 总标星超两万! 其实 ...