自学Android之UI组件:(一)ListView功能详解And实战
2017-03-11 17:59
387 查看
转载的老板请注明出处:http://blog.csdn.net/cc_xz/article/details/61422291 万分感谢!
前言:
从本篇开始讲解关于UI方面的内容,不过数量不会很多,这是因为,比较基础的UI例如Button等,网上的相关教程非常多,而且使用起来也比较简单。关于UI的大部分精力计划将放在RecyclerView等高级UI上,以及自定义View中。
而且从本篇开始,将以代码为主,再给予非常详细的注释来进行说明。话不多说,本篇开始。
通过本篇,你将了解到:
1.初步实现一个ListView。
2.对ListView进行优化。
实现使用ListView显示数据:
首先来看本篇文章实现的效果:
代码思路如下:
以下代码在activity_main中写入:
以下代码在MainActivity中写入:
以下代码在MainActivity的onCreate()中写入:
以下代码在新创建的GetSpurs类中写入:
以下代码在MainActivity中写入:
以下代码在新创建的SpursAdapter类中写入:
以下代码在新创建的list_item Layout中写入:
值得注意的是,当你在上面的布局文件中写出什么样子的布局,ListView就将以什么界面去显示布局。而且可能让你困惑的是,如果此时通过Android Studio的布局查看器查看当前布局,你会发现两个TextView只占了很少的部分,如下图:
这是因为,布局页面的垂直方向设置成了”horizontal”(水平方向),而最上层的LinearLayout中只有“两个”布局文件,分别是显示图片的ImageView和放置TextView的LinearLayout。
而我在放置TextView的LinearLayout中设置了”vertical”(垂直方向),又考虑到不同球员的名称长度、说明长度不同,所以并没有强行设置TextView的宽高,等到数据填充进去的时候,自动会根据数据源的大小而改变两个组件的大小。就像前面所展示的效果图一样。
以下代码在SpursAdapter的getView()中写入:
注意敲黑板,下面的代码是本篇的重中之重!!!
以下代码在SpursAdapter中写入:
以下代码在MainActivity的onCreate()中写入:
以上,你就可以试着运行程序了,这样实现的效果同前面展示的效果相同,再来看一遍,如下图所示:
分析现有的ListView:
好了,现在你的程序已经可以使用了,但是现在存在一个问题,那就是每当创建一个Icon,都会调用一次getView(),现在我们展示的内容还很少,只有10来条,而ListView中的组件也不多,只有3个(组件越多创建的对象越多)。但是现在毕竟只是测试环境,真正的APP上要显示的内容和组件数量要比现在多的多,虽然不会内存溢出,但是如果以现在的状态去运行,那么程序可能会被卡死。
那么这时候如果使用ViewHolder会提供程序运行效率,在不用ViewHolder的时候,每次调用getView方法,都会通过findViewById查找布局里的控件,这个是比较耗费时间的,使用ViewHolder可以把控件存储到ViewHolder里面,在使用时候直接从ViewHolder取出来就可以,这样能有效的提高程序效率。
现在来尝试优化一下。
优化ListView:
废话不多说,直接上代码:
以下代码在SpursAdapter中写入:
以下代码在SpursAdapter的getView()中重写入(原有代码注释掉):
后记:
本篇通过一个比较简单的ListView应用讲解了ListView的使用方式,主要是每个方法的功能、每个步骤的作用。后续的文章也会使用这种方式来书写。
另外,刚刚看了一下效果,发现代码中的注释看着效果还是比较晕,所以推荐把源码下载下载,直接使用Android Studio来观看,个人感觉效果还是比较好的。代码中的注释也比较全。
源码传送门:http://download.csdn.net/detail/cc_xz/9778113
前言:
从本篇开始讲解关于UI方面的内容,不过数量不会很多,这是因为,比较基础的UI例如Button等,网上的相关教程非常多,而且使用起来也比较简单。关于UI的大部分精力计划将放在RecyclerView等高级UI上,以及自定义View中。
而且从本篇开始,将以代码为主,再给予非常详细的注释来进行说明。话不多说,本篇开始。
通过本篇,你将了解到:
1.初步实现一个ListView。
2.对ListView进行优化。
实现使用ListView显示数据:
首先来看本篇文章实现的效果:
代码思路如下:
/** 代码思路: * 1.首先初始化所需组件,以及定义MainActivity的布局文件。 * 2.然后新建一个类定义ListView显示的数据格式。 * 3.通过ArrayList添加用于显示数据。 * 4.继承自BaseAdapter并定义Adapter的构造方法。 * 5.定义ListView布局页面。 * 6.定义Adapter的getView方法。 * 7.定义Adapter的其他方法。 * 8.应用Adapter。*/
以下代码在activity_main中写入:
<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:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/ListView"/> </LinearLayout>
以下代码在MainActivity中写入:
private String TAG = "来自于MainActivity"; private Context mContext; private SpursAdapter mAdapter; private ListView mListView; private ArrayList<GetSpurs> mListData;
以下代码在MainActivity的onCreate()中写入:
/* 代码执行1: * 1.将MainActivity的上下文环境作为参数传递给Context中,用于Adapter使用。 * 2.初始化ListView组件。值得注意的是,ListView是写在activity_main中的。 * 3.然后创建一个ArrayList对象,用于放置数据。*/ mContext = MainActivity.this; mListView = (ListView) findViewById(R.id.ListView); mListData = new ArrayList<>();
以下代码在新创建的GetSpurs类中写入:
/* 代码执行2: * 1.首先确定ListView都需要显示那些内容,然后根据显示的内容的格式来创建变量。 * 2.1.这里分别创建用于显示名称的String变量,显示说明的String变量以及显示头像的int类型变量。 * 2.2.值得注意的是,图片资源路径在Android是由R文件进行存储,而R文件存储的格式就是int类型。3 * 3.接着对应创建的变量,分别创建构造方法及get方法。 * 4.值得注意的是,很多文章中都创建是set方法,但是本篇中不会用到set方法,所以无需设置。*/ public class GetSpurs { private String TAG = "来自于GetSpurs"; private String mName; private String mExplain; private int mIcon; public GetSpurs(String name, String explain, int icon) { mName = name; mExplain = explain; mIcon = icon; } public String getName() { return mName; } public String getExplain() { return mExplain; } public int getIcon() { return mIcon; } }
以下代码在MainActivity中写入:
/* 代码执行3: * 1.通过创建好的ArrayList对象来将数据填充进去。 * 2.首先使用已经创建好的数据类型类(在前面创建ArrayList的时候已经指定了泛型)在.add()中新建一个内部匿名对象。 * 3.接着通过GetSpurs中的构造方法的的参数顺序来初始化希望在ListView中显示的数据的内容。 * 4.你可以按照我给出的数据来进行填充,也可以根据你自己的想法进行改造。*/ mListData.add(new GetSpurs("科怀·莱昂纳德","比赛终结者/窒息兄弟/马刺新领袖",R.drawable.im_spurs_1)); mListData.add(new GetSpurs("拉马库斯·阿尔德里奇","原中投小王子/现大里锋/马刺二当家/不是关键·篮板·不抢星人",R.drawable.im_spurs_2)); mListData.add(new GetSpurs("保罗·加索尔","进攻轴/速度巨慢/站撸抓冒",R.drawable.im_spurs_3)); mListData.add(new GetSpurs("托尼·帕克","法国自行车/小陀螺转/马刺掌舵者",R.drawable.im_spurs_4)); mListData.add(new GetSpurs("丹尼·格林","窒息兄弟/皇阿玛/不是关键·三分·不进星人",R.drawable.im_spurs_5)); mListData.add(new GetSpurs("帕蒂·米尔斯","米神/三分神经刀/XJBD小分队成员",R.drawable.im_spurs_6)); mListData.add(new GetSpurs("大卫·李","大腿李/篮下终结者/颜值帝",R.drawable.im_spurs_7)); mListData.add(new GetSpurs("马努·吉诺比利","妖刀/男神没有之一/XJBD小分队队长",R.drawable.im_spurs_8)); mListData.add(new GetSpurs("乔纳森·西蒙斯","身体爆劲/扣篮不进.....",R.drawable.im_spurs_9)); mListData.add(new GetSpurs("德维恩·戴德蒙","身体爆劲/真正蓝领/穷人小乔丹",R.drawable.im_spurs_10)); mListData.add(new GetSpurs("德章泰·穆雷","新秀一枚/潜力股",R.drawable.im_spurs_11));
以下代码在新创建的SpursAdapter类中写入:
/* 代码执行4: * 1.首先创建一个类型,用于继承自BaseAdapter。 * 2.继承完后,根据编译器的提示,重写出getCount()等方法。 * 3.接着定义Adapter中所需的变量。 * 4.1.然后创建构造方法,用于在MainActivity调用Adapter时传输参数。 * 4.2.第一个参数是在MainActivity中定义好的数据源,Adapter就是用于将数据源进行处理,然后显示到ListView中。 * 4.3.由于我们需要定义ListView的布局,所以需要获取布局中的ID,这需要一个Activity的上下文环境,所以将MainActivity的上下文环境传输至此。*/ public class SpursAdapter extends BaseAdapter{ private String TAG = "来自于SpursAdapter"; private ArrayList<GetSpurs> mListData; private Context mContext; public SpursAdapter(ArrayList<GetSpurs> listData, Context context){ mListData = listData; mContext = context; } @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; } }
以下代码在新创建的list_item Layout中写入:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <ImageView android:id="@+id/ImageView" android:layout_width="160dp" android:layout_height="140dp" android:paddingLeft="10dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/TextViewName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingTop="8dp" android:textColor="#AAAAAA" android:textSize="24sp" /> <TextView android:id="@+id/TextViewSays" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingTop="5dp" android:textColor="#72b6e3" android:textSize="17sp" /> </LinearLayout> </LinearLayout>
值得注意的是,当你在上面的布局文件中写出什么样子的布局,ListView就将以什么界面去显示布局。而且可能让你困惑的是,如果此时通过Android Studio的布局查看器查看当前布局,你会发现两个TextView只占了很少的部分,如下图:
这是因为,布局页面的垂直方向设置成了”horizontal”(水平方向),而最上层的LinearLayout中只有“两个”布局文件,分别是显示图片的ImageView和放置TextView的LinearLayout。
而我在放置TextView的LinearLayout中设置了”vertical”(垂直方向),又考虑到不同球员的名称长度、说明长度不同,所以并没有强行设置TextView的宽高,等到数据填充进去的时候,自动会根据数据源的大小而改变两个组件的大小。就像前面所展示的效果图一样。
以下代码在SpursAdapter的getView()中写入:
注意敲黑板,下面的代码是本篇的重中之重!!!
/* 代码执行6: * 1.1.getView()是Adapter中最重要的接口回调,它用于将需要在视图中显示的数据同显示数据的组件进行绑定。 * 1.2.每增加一个Icon,则需要调用一次getView,用于创建Icon。 * 2.1.getView提供了三个参数,第一个参数为当前显示的Icon的位置,即:第一个Icon对应的值为0,第10个Icon对应的值为9。 * 2.2.converView则是一个用于获取View布局文件的对象,我们通过mContext对象中存储的MainActivity的上下文交给它,从而获得用于ListView显示的布局文件。 * 2.3.第三个参数是ViewGroup,即是否要定义这个ListView的父View。此处暂且不表。*/ @Override public View getView(int position, View convertView, ViewGroup parent) { /* 代码执行6: * 1.1.首先通过LayoutInflater的.from()获取到一个Activity的上下文环境,即需要添加的Layout是依附哪个Activity上显示。 * 1.2.接着通过inflate()来获取定义好的Layout,即当前ListView显示的布局文件。 * 1.3.后面的null,就是添加的ListView的父View,可以添加一个ViewGroup类型的父布局,如果不需要也可以填写为null。 * 2.1.然后分别创建ListView布局文件中的三个组件的对象,但是值得注意的是,在获取ID时同在Activity中直接获取不同。 * 2.2.是通过定义好的convertView来调用findViewById()。 * 2.3.这是因为当前类并不是Activity,所以并不具有获取ID的方法,但是通过LayoutInflater可以获取到一个布局,且返回格式为View。 * 2.4.这就表示通过了一个定义好的View视图来获取ID,即获取这个定义好的View中你的组件ID。 * 3.1.之后分别给三个组件进行赋值。 * 3.2.所赋的值全部来自于在MainActivity中定义好的ArrayList,通过get(),这时就使用到了position参数。即:当前要显示哪个Icon,就从对应的ArrayList中取出对应的数据。 * 3.3.由于定义的ArrayList是通过GetSpurs定义的数据格式,当取出数据时,也需要通过GetSpurs的getXXX()来获取数据。(暂时还用不到set方法)。 * 4.1.再次强调一遍,每显示一个Icon,就调用一次getView(),所以每次都把新的View视图(convertView)返回给ListView(这里是Adapter)。*/ convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, null); ImageView imageView = (ImageView) convertView.findViewById(R.id.ImageView); TextView textViewName = (TextView) convertView.findViewById(R.id.TextViewName); TextView textViewSays = (TextView) convertView.findViewById(R.id.TextViewSays); imageView.setBackgroundResource(mListData.get(position).getIcon()); textViewName.setText(mListData.get(position).getName()); textViewSays.setText(mListData.get(position).getExplain()); return convertView; }
以下代码在SpursAdapter中写入:
/* 代码执行7: * 1.1.首先定义getCount(),该方法是在ListView开始创建前,获取ListView所显示的长度的。 * 1.2.所以返回数据源的长度,告知ListView本次需要显示多少条数据。 * 2.1.getItem()是用于定义ListView中显示的组件类型,暂时设置null即可,下篇文章设置此处。 * 3.1.getItemId即返回与getItem()对应的ListView显示位置。*/ @Override public int getCount() { return mListData.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; }
以下代码在MainActivity的onCreate()中写入:
/* 代码执行8: * 1.首先创建SpursAdapter为对象,并且根据构造方法,将当前的数据源和上下文环境作为参数。(回想一下这两个参数的作用?) * 2.接着,将定义好的Adapter应用到ListView中,此时ListView开始工作,显示内容。*/ mAdapter = new SpursAdapter(mListData, mContext); mListView.setAdapter(mAdapter);
以上,你就可以试着运行程序了,这样实现的效果同前面展示的效果相同,再来看一遍,如下图所示:
分析现有的ListView:
好了,现在你的程序已经可以使用了,但是现在存在一个问题,那就是每当创建一个Icon,都会调用一次getView(),现在我们展示的内容还很少,只有10来条,而ListView中的组件也不多,只有3个(组件越多创建的对象越多)。但是现在毕竟只是测试环境,真正的APP上要显示的内容和组件数量要比现在多的多,虽然不会内存溢出,但是如果以现在的状态去运行,那么程序可能会被卡死。
那么这时候如果使用ViewHolder会提供程序运行效率,在不用ViewHolder的时候,每次调用getView方法,都会通过findViewById查找布局里的控件,这个是比较耗费时间的,使用ViewHolder可以把控件存储到ViewHolder里面,在使用时候直接从ViewHolder取出来就可以,这样能有效的提高程序效率。
现在来尝试优化一下。
优化ListView:
废话不多说,直接上代码:
以下代码在SpursAdapter中写入:
/* 代码执行9: * 1.首先创建一个ViewHolder子类,在这个类中创建我们所需要的组件静态变量。 * 2.要知道,ViewHolder并不是Java或Android提供给我们的一种API,而是一种编程方式。 * 3.这是因为,原来每次新增一个Icon,都需要调用一次getView(),而每调用一次getView(),里面的所有对象、变量都会被重写创建。 * 4.于是采用这种方式,用来保存对象,配合if判断,就可以实现只有在第一次调用getView()创建对象,后面的使用原有对象即可。*/ public class ViewHolder { ImageView imageView; TextView textViewName; TextView textViewSays; }
以下代码在SpursAdapter的getView()中重写入(原有代码注释掉):
/* 代码执行9: * 1.首先创建并初始化ViewHolder对象,用于获取其中与组件所对应的对象。 * 2.1.接着判断当前getView()接口传递来的convertView若为不空,则表示已经使用过ListView,无需创建对象,直接调用viewHolder即可。 * 2.2.反之,如果convertView如果为空,则表示是第一次使用ListView,则需要创建各个对象。 * 3.如果已经使用过ListView,则只需通过getTag()将打入的TAG(标记)取出,便可以获得已经完成的初始化操作(对象中包含的组件对象的赋值)。 * 4.1.如果没有使用过ListView,除了获取布局和通过ViewHolder获得组件ID外,还需要打标签。 * 4.2.打标签是指,将ViewHolder现有的信息,即对象初始化数据,通过标签的形式打入converView中,再通过第三步取出,则无需再次初始化组件。*/ ViewHolder viewHolder = new ViewHolder(); if (convertView != null) { viewHolder = (ViewHolder) convertView.getTag(); } else { convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, null); viewHolder.imageView = (ImageView) convertView.findViewById(R.id.ImageView); viewHolder.textViewName = (TextView) convertView.findViewById(R.id.TextViewName); viewHolder.textViewSays = (TextView) convertView.findViewById(R.id.TextViewSays); convertView.setTag(viewHolder); } /* 代码执行9: * 1.设置数据的方式同原来的方式大致形同,但是通过ViewHolder获取组件对象来获取ID。*/ viewHolder.imageView.setBackgroundResource(mListData.get(position).getIcon()); viewHolder.textViewName.setText(mListData.get(position).getName()); viewHolder.textViewSays.setText(mListData.get(position).getExplain());
后记:
本篇通过一个比较简单的ListView应用讲解了ListView的使用方式,主要是每个方法的功能、每个步骤的作用。后续的文章也会使用这种方式来书写。
另外,刚刚看了一下效果,发现代码中的注释看着效果还是比较晕,所以推荐把源码下载下载,直接使用Android Studio来观看,个人感觉效果还是比较好的。代码中的注释也比较全。
源码传送门:http://download.csdn.net/detail/cc_xz/9778113
相关文章推荐
- Android编程之ListView和EditText发布帖子隐藏软键盘功能详解
- 【Android实战】记录自学自定义GifView过程,详解属性那些事!【学习篇】
- Android用户界面 UI组件--AdapterView及其子类(一) ListView及各种Adapter详解
- 【Android】Listview返回顶部,快速返回顶部的功能实现,详解代码。
- Android UI组件----ListView列表控件详解
- Android用户界面 UI组件--AdapterView及其子类(一) ListView及各种Adapter详解
- QtAndroid详解(3):startActivity实战Android拍照功能
- Android用户界面 UI组件--AdapterView及其子类(一) ListView及各种Adapter详解
- [置顶] 【Android】Listview返回顶部,快速返回顶部的功能实现,详解代码。
- Android实战开发之CheckBox+ListView长按多选增删改查功能完美实现步骤
- QtAndroid详解(3):startActivity实战Android拍照功能
- android ListView详解
- Android中ICS4.0Launcher中Fold的功能详解【androidICS4.0-->Launcher系列三】
- Android实战技术:ListView刷新的顺序问题
- Android实现ListView过滤功能,继承于BaseAdapter
- Android软件开发之ListView 详解
- android ListView详解
- Android ListView详解
- android ListView详解
- 分享个刚写好的 android 的 ListView 动态加载类,功能全而代码少。