最近由于项目需要,要实现一个横向滚动的列表,打算直接用HorizontalScrollView,但是因为没有视图复用,列表项多了之后会占用较多内存,排除;再想到用Gallery,但Gallery有一个自动定位到中央的动画效果,要去除这个效果的工作比较复杂。最后搜了一下找到了这个
Android-HorizontalListView,实现了ListView的大部分功能,只是不支持Header、Footer和ScrollBar,项目要求提供Scroolbar的显示,所以就在上面动手吧,添加横向的Scrollbar。
下面添加scrollbar相关的计算
这里参考了AbsListView中的实现,上面的计算过程比较容易理解,×100是为了保持两位小数的精度。range的值就是总的列表项个数(mAdapter.getCount());滑块的大小extent是当前显示的个数,然后去除左右边界超出的部分来提高精度;offset是显示的第一个列表的索引值。也就是说上面采用了“个数”为度量单位进行计算。
ScrollBar作为一个基础功能被实现在View中,子类需要实现computeXXXScrollRange、computeXXXScrollExtent和computeXXXScrollOffset这三个方法,其中:
1、computeXXXScrollRange,计算滚动条的滚动范围
2、computeXXXScrollExtent,计算滑块显示的大小
3、computeXXXScrollOffset,计算滚动的偏移量,也就是当前滚动的位置
上面这三个方法返回的值都是相对值,也就是计算的时候采用一个统一的度量,具体视图上的显示在View的onDrawScrollbar()方法中已经实现。
有了这三个方法之后,还需要调用在滚动的过程中调用awakenScrollbars(),因为Scrollbar在停止滚动后会自动隐藏,所以就需要在滚动的时候不断唤起scrollbar让它显示出来,也就是这个方法。
HorizontalListView通过监听滚动手势来不断requestLayout,重新布局列表的显示来达到滚动的效果,所以awakenScrollbars这个方法就添加在onLayout中。
- protected void onLayout(boolean changed, int left, int top, int right,
- int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (mAdapter == null) {
- return;
- }
- // Force the OS to redraw this view
- if (!awakenScrollBars()) {
- postInvalidate();
- }
- ...
- }
下面添加scrollbar相关的计算
- @Override
- protected int computeHorizontalScrollRange() {
- int count = mAdapter.getCount();
- return Math.max(count * 100, 0);
- }
- @Override
- protected int computeHorizontalScrollExtent() {
- int count = getChildCount();
- if (count > 0) {
- int extent = count * 100;
- View view = getChildAt(0);
- final int left = view.getLeft();
- int width = view.getWidth();
- if (width > 0) {
- extent += (left * 100) / width;
- }
- view = getChildAt(count - 1);
- final int right = view.getRight();
- width = view.getWidth();
- if (width > 0) {
- extent -= ((right - getWidth()) * 100) / width;
- }
- return extent;
- }
- return 0;
- }
- @Override
- protected int computeHorizontalScrollOffset() {
- final int firstPosition = mLeftViewAdapterIndex;
- final int childCount = getChildCount();
- if (firstPosition >= 0 && childCount > 0) {
- final View view = getChildAt(0);
- final int left = view.getLeft();
- int width = view.getWidth();
- if (width > 0) {
- int result = Math.max(firstPosition * 100 - (left * 100) / width, 0);
- return result;
- }
- }
- return 0;
- }
这里参考了AbsListView中的实现,上面的计算过程比较容易理解,×100是为了保持两位小数的精度。range的值就是总的列表项个数(mAdapter.getCount());滑块的大小extent是当前显示的个数,然后去除左右边界超出的部分来提高精度;offset是显示的第一个列表的索引值。也就是说上面采用了“个数”为度量单位进行计算。
FROm:http://blog.csdn.net/xu_fu/article/details/41792657