Android常用控件-ListView
来源:互联网 发布:日立n3000知乎 编辑:程序博客网 时间:2024/05/22 08:55
由于手机屏幕有限, 所以ListView的使用非常的普遍. ListView就是用户可以通过手指上下滑动的方式来展现更多的数据.
ListView的简单使用:
新建一个ListViewDemo的项目,修改activity-main.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="match_parent" android:orientation="vertical"> <ListView android:id="@+id/list_view_demo" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView></LinearLayout>
为ListView指定一个id, 这样就会在页面出现一个ListView的基本布局.
下面是MainAcitivity中代码:
import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.widget.ArrayAdapter;import android.widget.ListView;public class MainActivity extends AppCompatActivity { private String[] data = {"爸爸","妈妈","姐姐","妹妹","二姑","三姑", "四舅","五伯","哥哥","嫂嫂","爷爷","奶奶","姥姥","姥爷"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //android.R.layout.simple_list_item_1 作为ListView子项布局的id, // 这是一个android内置的布局文件, 里面只有一个textview //可用于简单的显示一段文本. ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data); ListView listView = (ListView)findViewById(R.id.list_view_demo); listView.setAdapter(adapter); }}
ListView是用来展示大量数据的, 这里用了一个数组. 数组中的数据是无法直接传递给ListView的, 需要借助适配器来传递. 由于这里提供的数据都是字符串,因此将ArrayAdapter的泛型指定为String, 依次传递参数为, 上下文, 子项布局id, 数据.
ListView的setAdapter()方法表示将建好的设配器对象传递给listview, 这样页面和数据就进行了关联.
运行效果:
定制ListView的界面
正式的项目开发中, 不可能使用这么简单的, 很多情况是需要根据客户的需求, 进行定制开发, 下面我们就对上面的ListView进行简单的扩展.
我们把这个列表扩展成一个简单的通讯录功能功能, 会显示头像, 昵称, 和电话.
我们首先定义一个实体类, 作为ListView适配器的适配类型. 新建类Family, 代码如下:
public class Family { private String name; private int imageID; private int phoneNum; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getImageID() { return imageID; } public void setImageID(int imageID) { this.imageID = imageID; } public int getPhoneNum() { return phoneNum; } public void setPhoneNum(int phoneNum) { this.phoneNum = phoneNum; }}
name:表示称呼
imageID: 表示头像id
phoneNum: 表示电话号码
我们需要为ListView的子项指定一个我们自定义的布局, 在layout的目录下新建family_item.xml, 代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/family_image" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/family_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp"/> <TextView android:id="@+id/family_phone_num" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp"/></LinearLayout>
在这个布局中, 定义了ImageView用于显示头像, TextView分别用来显示称谓和电话. 并且让TextView在垂直方向居中显示.
接下来我们需要创建自定义的适配器, 这个适配器继承ArrayAdapter, 并将泛型定义为Family类. 新建类FamilyAdapter, 代码如下:
public class FamilyAdapter extends ArrayAdapter<Family>{ private int resourceID; public FamilyAdapter(Context context, int resource, List<Family> objects) { super(context, resource, objects); resourceID = resource; } @NonNull @Override public View getView(int position, View convertView, ViewGroup parent) { Family family = getItem(position); // 获取当前项的Family实例 View view = LayoutInflater.from(getContext()).inflate(resourceID, parent, false); ImageView familyImage = (ImageView) view.findViewById(R.id.family_image); TextView familyName = (TextView) view.findViewById(R.id.family_name); TextView familyPhone = (TextView) view.findViewById(R.id.family_phone_num); familyImage.setImageResource(family.getImageID()); familyName.setText(family.getName()); familyPhone.setText(family.getPhoneNum()); return view; }}
FamilyAdapter重写了父类的一组构造函数, 用于将上下文, ListView子项布局的id和数据都传递进来. 另外又重写了一个getView()方法, 这个方法在每个子项被滚动到屏幕内的时候会被调用.
在getView()中, 首先通过getItem()方法得到当前项的Family实例, 然后使用LayoutInflater来为这个子项加载我们传入的布局.
这里LayoutInflater的inflate()方法接收3个参数, inflate()可以动态加载一个布局文件的id, 布局id, 第二个参数是给加载好的布局添加一个父布局.第三个参数指定成false, 表示只将我们在父布局中声明的layout属性生效, 但不为这个View添加父布局, 因为一旦view有了父布局之后, 它就不能再添加到ListView中了.
之后我们调用View的findViewById()方法分别获取到ImageView和TextView的实例. 并分别调用他们的setImageResource()和setText()方法来设置显示的图片和文字, 最后将布局完成.
下面来修改MainActivity中的代码.
public class MainActivity extends AppCompatActivity { private List<Family> familyList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initFamilys();// 初始化家庭数据 FamilyAdapter adapter = new FamilyAdapter(MainActivity.this,R.layout.family_item,familyList); ListView listView = (ListView)findViewById(R.id.list_view_demo); listView.setAdapter(adapter); } private void initFamilys() { for(int i= 0; i<2; i++){ Family family1 = new Family("爸爸", R.mipmap.family_1, "13813813888"); familyList.add(family1); Family family2 = new Family("妈妈", R.mipmap.family_2, "13813813888"); familyList.add(family2); Family family3 = new Family("姐姐", R.mipmap.family_1, "13813813888"); familyList.add(family3); Family family4 = new Family("三姑", R.mipmap.family_2, "13813813888"); familyList.add(family4); Family family5 = new Family("妹妹", R.mipmap.family_1, "13813813888"); familyList.add(family5); Family family6 = new Family("二姑", R.mipmap.family_1, "13813813888"); familyList.add(family6); Family family7 = new Family("三姑", R.mipmap.family_2, "13813813888"); familyList.add(family7); Family family8 = new Family("四舅", R.mipmap.family_1, "13813813888"); familyList.add(family8); Family family9 = new Family("三姑", R.mipmap.family_2, "13813813888"); familyList.add(family9); Family family10 = new Family("哥哥", R.mipmap.family_1, "13813813888"); familyList.add(family10); Family family11 = new Family("嫂嫂", R.mipmap.family_1, "13813813888"); familyList.add(family11); Family family12 = new Family("爷爷", R.mipmap.family_2, "13813813888"); familyList.add(family12); Family family13 = new Family("奶奶", R.mipmap.family_1, "13813813888"); familyList.add(family13); Family family14 = new Family("姥姥", R.mipmap.family_2, "13813813888"); familyList.add(family14); Family family15 = new Family("姥爷", R.mipmap.family_1, "13813813888"); familyList.add(family15); } }}
运行效果:
相信你已经领悟到了诀窍, 只要修改family_item.xml中的内容, 就可以定制出各种复杂的界面了.
提升ListView的运行效率
之所以说ListView很难用, 是因为它有很多细节可以优化. 其中效率就是很重要的一点. 目前我们的运行效率极低, 是因为FamilyAdapter的getView()方法中, 每次都将布局重新加载一遍, 当ListView快速滚动的时候, 就会出现性能的瓶颈.
在getView()方法中还有一个converView参数, 这个参数用于将之前加载好的布局进行缓存, 以便之后可以重用. 所以修改代码如下:
Family family = getItem(position); // 获取当前项的Family实例 View view; if(convertView == null){ view = LayoutInflater.from(getContext()).inflate(resourceID, parent, false); } else { view = convertView; }
convertView 为null的时候, 才去加载布局, 如果不为null, 则直接重用convertView. 这样就大大提高了ListView的运行效率. 加快滚动的时候也可以出现很好的性能.
当然这部分代码还是可以继续优化的, 虽然现在不会再去重复加载布局, 但是每次在getView()方法中还是会调用View的findViewById()方法来获取一次控件的实例.
我们可以借助一个ViewHolder来对这部分性能进行优化. 修改FamilyAdapter中的优化代码.
public View getView(int position, View convertView, ViewGroup parent) { Family family = getItem(position); // 获取当前项的Family实例 View view; ViewHolder viewHolder; if(convertView == null){ view = LayoutInflater.from(getContext()).inflate(resourceID, parent, false); viewHolder = new ViewHolder(); viewHolder.familyImage = (ImageView) view.findViewById(R.id.family_image); viewHolder.familyName = (TextView) view.findViewById(R.id.family_name); viewHolder.familyPhone = (TextView) view.findViewById(R.id.family_phone_num); view.setTag(viewHolder); //将ViewHolder储存在View中 } else { view = convertView; viewHolder = (ViewHolder) view.getTag();// 重新获取ViewHolder } viewHolder.familyImage.setImageResource(family.getImageID()); viewHolder.familyName.setText(family.getName()); viewHolder.familyPhone.setText(family.getPhoneNum()); return view; } class ViewHolder { ImageView familyImage; TextView familyName; TextView familyPhone; }
解读:
新增的ViewHolder用于对控件的实例进行缓存, 当convertView为null的时候, 创建一个ViewHolder对象, 并将控件实例都存在ViewHolder里, 然后调用view的setTag()方法, 将ViewHolder对象储存在view中.
当convertView不为null的时候, 则调用View的getTag()方法, 把ViewHolder重新取出. 这样所有的控件实例都缓存在了ViewHolder里面. 就没有必要每次通过findViewById()方法来获取控件实例了.
运行效果:
源码如下:
https://github.com/junzaivip/ListViewDemo
- Android常用控件:ListView
- Android常用控件-ListView
- Android常用控件:ListView(2)
- Android常用控件:ListView(3)
- Android常用控件(二)【ProgressBar、ListView】
- Android常用控件之SimpleAdapter和ListView
- Android常用复杂控件使用(二)--ListView
- Android的常用基本控件ImageView、ListView
- Android常用控件之ListView(一)
- Android常用控件--ListView的简单使用
- Android常用控件之ListView(二)
- Android项目常用控件之ListView
- Android的ListView控件的常用适配器
- 常用控件之listview
- 常用控件之listview
- 2.常用控件:ListView
- android常用控件(三)- ProgressBar、ListView
- Android学习笔记8——常用控件ListView
- 10603UVA倒水
- VS2008中导入EXCEL文件数据(Unicode版本下)
- Android 查看及设置 SELinux 状态
- Android之HelloWorld
- 在MFC对话框中显示html网页
- Android常用控件-ListView
- java基础学习API之Date,DateFormat和Calendar 六-4
- 安卓的系统架构(随笔)
- Java面试题-基本语法
- CSS3的基础知识
- C++ 输出各种图形
- 收录的Java Web基础面试题
- git使用入门-常用命令
- Springmvc关于拦截所有网址的一个致命错误,需注意!