在Android 5.X时代,RecyclerView逐渐取代ListView,但ListView使用范围依然广泛。
1. ListView常用优化技巧
1.1. 使用ViewHolder模式提高效率
ViewHolder模式利用ListView的视图缓存机制,避免每次调用getView()
时都通过findViewById()
实例化控件。使用ViewHolder和BaseAdapter比不使用ViewHolder的BaseAdapter提高50%以上效率。
convertView.setTag(holder);
,再次getView()
通过tag找到缓存的布局
1.2. 设置项目分隔线
android:divider="@android:color/darker_gray"
android:dividerHeight="10dp"
分隔线不仅可以设置为颜色,也可设置为一个图片资源
分隔线设置为透明:android:divider="@null"
1.3. 隐藏ListView的滚动条
android:scrollbars="none"
1.4. 取消ListView的Item点击效果
android:listSelector="#00000000"
或
android:listSelector="@android:color/transparent"
1.5. 设置ListView需要显示在第几项
需要显示第N个Item:listView.setSelection(N);
,类似scrollTo
实现平滑移动:
mListView.smoothScrollBy(distance, duration);
mListView.smoothScrollByOffset(offset);
mListView.smoothScrollToPosition(index);
1.6. 动态修改ListView
mData.add("new");
mAdapter.notifyDataSetChanged();
mData必须是mAdapter的原数据源
1.7. 遍历ListView中的所有Item
获取第i个子View:mListView.getChildAt(i);
1.8. 处理空ListView
ListView无数据时给予提示:listView.setEmptyView(findViewById(R.id.empty_view));
1.9. ListView滑动监听
- OnTouchListener
监听ACTION_DOWN
、ACTION_MOVE
、ACTION_UP
这三个事件 - OnScrollListener
OnScrollListener是AbsListView中的监听事件,有两个回调方法——onScrollStateChanged()
和onScroll()
onScrollStateChanged
方法根据参数scrollState
决定回调次数,scrollState
有三种模式:
OnScrollListener.SCROLL_STATE_TOUCH_SCROLL
:正在滚动时
OnScrollListener.SCROLL_STATE_FLING
:手指抛动时
OnScrollListener.SCROLL_STATE_IDLE
:滚动停止时
当用户没有做手指抛动状态时,这个方法只回调2次,否则回调3次。
onScroll(AbsListView view, int firstVisibleItem, int visibleCount, int totalItemCount)
方法在ListView滚动时会一直回调
mListView.getLastVisiblePosition() // 获取可视区域内最后一个Item的id
mListView.getFirstVisiblePosition() // 获取可视区域内第一个Item的id
2. ListView常用拓展
2.1. 具有弹性的ListView
主要学会如何从源代码中找到问题的解决方法
重写overScrollBy
方法,并将参数maxOverScrollY
由默认值0改为设定值
为满足多分辨率的需求,可在修改maxOverScrollY
值时通过屏幕的density来计算具体的值,让不同分辨率的弹性距离基本一致
2.2. 自动显示、隐藏布局的ListView
实现效果:Toolbar显示在最上方,当向上滑动时,Toolbar隐藏,再向下滑动时,Toolbar显示
先给ListView增加一个HeaderView,避免第一个Item被Toolbar遮挡,高度为ActionBar的高度。
获取系统认为的最低滑动距离:mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
判断滑动事件,通过滑动点的坐标改变大小,来判断移动的方向,并根据移动方向执行不同的动画效果。
最后加上控制布局显示隐藏的动画。
Google推荐用Toolbar逐渐取代ActionBar,因其更灵活,需引入编译:
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:21.0.3'
}
2.3. 聊天ListView
在定义BaseAdapter,重写getView()
方法时,判断获取哪一种布局。通过重写BaseAdapter的两个方法:
getItemViewType(int position)
方法返回第position个Item是何种类型
getViewTypeCount()
方法返回不同布局的总数
聊天信息内容的TextView使用9patch的图片,横向拉伸。
封装一个Bean来保存聊天信息,声明需要的信息并提供get和set方法。
2.4. 动态改变listView布局
如果要动态地改变点击Item的布局来达到一个Focus的效果,一般有两种方法:
1) 将两种布局写在一起,通过控制布局的显示、隐藏,来达到切换布局的效果
2) 在getView()
的时候,通过判断来选择加载不同的布局:
1. 给Item制作两种不同的布局——Focus和Normal
2. 在getView()
方法中,通过判断点击的位置来改变相应的视图
3. ListView在点击后,设置点击位置,使用notifyDataSetChanged()
方法来实现刷新布局的功能