ListView常用优化技巧
使用ViewHolder模式提高效率
ViewHolder模式是提高ListView效率的一个重要的方法。ViewHolder模式充分利用了ListView的视图缓存机制,避免了每次在调用getView()的时候都去通过findViewById()实例化控件。据测试,使用ViewHolder将提高50%以上的效率。使用ViewHolder模式来优化ListView非常简单,只需要在自定义Adapter中定义一个内部类ViewHolder,并将布局中的控件作为成员变量。
|
|
接下来,只要在getView()方法中通过视图缓存机制来重用以缓存即可。
|
|
设置项目分隔线
ListView的各个项目之间,可以通过设置分割线来进行区分,系统提供了diver和diverHeight这样两个属性来实现这一功能。通过这两个属性,也可以控制机ListView之间的分割线和它的高度。当然,分割线不仅仅可以设置为一个颜色,同样也可以设置为一个图片资源,分割线的使用代码如下所示。
|
|
特殊情况下,当设置分隔线为null时,就可以把分隔线设置为透明了。
|
|
divider的源码实现如下。
|
|
|
|
在dispatchDraw()方法里面会计算出每一个divider的bounds范围最终通过drawDivider()方法绘制到canvas上面。
隐藏ListView的滚动条
默认的ListView在滚动时,在右边会显示滚动条,指示当前滑动的位置,我们可以设置scrollbars属性,控制ListView的滚动条状态。特别的,当设置scrollbars属性为none的时候,ListView滚动或者不滚动,就都不会出现滚动条了。
|
|
取消ListView的item点击效果
当点击ListView中的一项时,系统会默认出现一个点击效果,在android5.x上是一个波纹效果,而在android5.x之下的版本则是一个改变背景颜色的效果,但可以通过修改listSelector属性来取消掉点击后的回馈效果。
|
|
当然,也可以直接使用android自带的透明色来实现这个效果。
|
|
设置ListView需要在显示在第几页
ListView以Item为单位进行显示,默认显示在第一个Item,当需要指定显示的Item时,可以通过如下代码来实现。
|
|
其中N就是需要显示的第N个Item。
当然,这个方法类似srcollTo,是瞬间完成的移动。除此之外,还可以通过如下代码来实现平滑移动。
|
|
动态修改ListView
ListView中的数据在某些情况下是需要变化的,当然可以通过重新设置ListView的Adapter来更新ListView的显示,但这也就需要重新获取一下数据,相当于重新创建ListView,这样显然不是非常友好,而且效率也不会太高。因此,可以使用一个简单的方法来哦实现ListView的动态修改,代码如下所示。
|
|
当修改了传递给Adapter的映射List之后,只需要通过调用Adapter的notifyDataSetChanged()方法,通知ListView更改数据源即可完成对ListView的动态修改。不过,使用这个方法有一点需要注意的是,在使用mAdapter.notifyDataSetChanged()方法时,必须保证传进Adapter的数据List是同一个List而不能是其他对象,否则将无法实现该效果。
遍历ListView中所有item
ListView作为一个ViewGroup,为我们提供了操纵子View的各种方法,最常用的就是通过getChildAt()来获取第i个子View。
|
|
处理空ListView
ListView用于展示列表数据,但当列表中无数据时,ListView不会显示任何数据或提示,按照完善用户体验得到需求,这里应该给以无数据的提示。ListView提供了一个方法——setEmptyView(),通过这个方法可以给ListView设置一个在空数据下显示的默认提示。
|
|
通过以上代码,就给ListView在空数据时显示一张默认的图片,用来提示用户,而在有数据时,就不会显示。
ListView滑动监听
ListView的滑动监听,是ListView中最重要的技巧,很多重写的ListView,基本上都是在滑动事件的处理上下功夫,通过判断滑动事件进行不同的逻辑处理。而为了更加准确地监听滑动事件,开发者通常还需要使用GestureDetector手势识别,VelocityTracker滑动速度检测等辅助类来完成更好的监听。这里介绍两种监听ListView滑动事件的方法,一个是通过OnTouchListener来实现监听,另一个是使用OnScrollListener来实现监听。
OnTouchListener
OnTouchListener是View中的监听事件,通常监听ACTION_DOWN、ACTION_MOVE、ACTION_UP这三个事件发生时的坐标,就可以根据坐标判断用户滑动的方向,并在不同的事件中进行相应的逻辑处理,这种方式的使用代码如下所示。
12345678910111213141516mListView.setOnTouchListener(new View.OnTouchListener() {public boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:break;case MotionEvent.ACTION_MOVE:break;case MotionEvent.ACTION_UP:break;default:break;}return false;}});OnScrollListener
OnScrollListener是AbsListView中的监听事件,他封装了很多与ListView相关的信息,使用起来也更加灵活。首先来看一下OnScrollListener的一般使用方法。
123456789101112131415161718192021222324mListView.setOnScrollListener(new AbsListView.OnScrollListener() {public void onScrollStateChanged(AbsListView view, int scrollState) {switch (scrollState) {case SCROLL_STATE_IDLE:// 滑动停止时break;case SCROLL_STATE_TOUCH_SCROLL:// 正在滚动break;case SCROLL_STATE_FLING:// 手指抛动时,即手指用例滑动,在离开后ListView由于惯性继续滑动break;default:break;}}public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {// 滚动时一直调用,firstVisibleItem表示当前的第一个Item的ID(从0开始), visibleItemCount表示当前能看见的Item总数,totalItemCount表示整个ListView的Item总数}});通过onScroll()方法提供的几个参数,可以方便地进行一些判断,比如判断是否滚动到最后一行,当前可视的第一个Item的ID加上当前当前可视Item的和等于Item总数的时候,即滚动到了最后一行。
123if (firstVisiableItem + visibleItemCount == totalItemCount && totalItemCount > 0) {//滚动到最后一行}再比如,可以判断滚动的方向,通过一格成员变量lastVisiableItemPostion来记录上次第一个可视的Item的ID并与当前的可视Item的ID进行比较,即可知道当前滚动的方向。
123456if (firstVisiableItem > lastVisiableItemPostion) {// 上滑} else if(firstVisiableItem < lastVisiableItemPostion) {// 下滑}lastVisiableItemPostion = firstVisiableItem;当然,ListView也给我们提供了一些封装的方法来获取当前可视的Item的位置等信息。
1234// 获取可视区域最后一个Item的idmListView.getLastVisiablePosition();// 获取可视区域内第一个Item的idmListView.getFirstVisiablePosition();
ListView常用扩展
ListView虽然使用广泛,但系统原生的ListView显然是不能满足用户在审美、功能上不断提高需求的。不过也不要紧,android完全可以定制化,让我们非常方便地对原生ListView进行扩展、修改。于是,在开发者的创新下,ListView越来越丰富多彩,各种各样的基于原生ListView的扩展让人目不暇接。下面来看几个常用的ListView扩展。
具有弹性的ListView
android默认的ListView在滚动到顶端或者底端的时候,并没有很好的提示。在android5.x中,Google为这样的行为值添加了一个半月形的阴影效果。而在iOS系统中,列表都是具有弹性的,即滚动到底端后继续往下或者往上滑动一段距离。
重写ListView来实现弹性效果的方法有很多,比如增加HeaderView或者使用ScrollView进行嵌套。通过查看ListView源代码的时候可以发现,ListView中有一个控制滑动到边缘的处理方法。
|
|
可以看见这样一个参数,maxOverScrollY,这个值默认为0,但其实只要修改这个参数的值,就可以让ListView具有弹性了。当然,为了能够满足多分辨率的需求,可以在修改的时候通过屏幕的density来计算具体的值,让不同分辨率的弹性距离基本一致。
自动显示、隐藏布局的ListView
Google+有这样一个效果,当我们在ListView上滑动的时候,顶部的ActionBar或者ToolBar就会相应的隐藏或显示。我们知道,让一个布局显示或者隐藏并带有动画效果,可以通过属性动画来很方便地实现,所以这个效果关键就在于如何获得ListView的各种滑动事件。所以借助OnTouchListener接口来监听ListView的滑动,通过比较与上次坐标的大小,来判断滑动的方向,并通过滑动的方向来判断是否需要显示或者隐藏对应的布局。在开始判断滑动事件之前,还要做一些准备工作,首先需要给ListView增加一个HeaderView,避免第一个Item被Toolbar遮挡。
|
|
另外,定义一个mTouchSlop变量用来获取系统认为的最低滑动距离,即超过这个距离的移动,系统就将其定义为滑动状态。
|
|
有了前面的准备工作,下面就可以判断滑动的事件了。
|
|
代码逻辑非常简单,只是通过滑动点的坐标改变大小,来判断移动的方向,并根据移动方向来执行不同的动画效果。
有了前面的分析,实现这样一个效果就非常简单了,最后加上控制布局显示隐藏的动画,如下所示。
|
|