Android 自己动手写ListView学习其原理 2 上下滚动

来源:互联网 发布:在手机上怎么做淘宝客? 编辑:程序博客网 时间:2024/04/30 15:28



《Android 自己动手写ListView学习其原理 1 显示第一屏Item》

 《Android 自己动手写ListView学习其原理 2 上下滚动》

《Android 自己动手写ListView学习其原理 3 ItemClick,ItemLongClick,View复用》


        之前已经写了《Android 自己动手写ListView学习其原理 1 显示第一屏Item》 可以看到显示了一屏幕的Item但是并不能滚动,当前添加滚动功能。

        ListView滚动如何实现呢?滚动操作时触摸视图,在视图上滑动之后ListView才会跟随手指滚动,这就很明确必须覆写onTouchEvent方法进行接收Touch事件并进行相应处理。



一、有图有真相



二、覆写onTouchEvent

在按下的时候进行一些参数的初始化,移动的时候有多种状态,其状态值由mTouchMode变量记录,当前定义三种状态

    // 初始模式,用户还未接触ListView    private static final int TOUCH_MODE_REST = -1;    // 触摸Down事件模式    private static final int TOUCH_MODE_DOWN = 0;    // 滚动模式    private static final int TOUCH_MODE_SCROLL = 1;

onTouchEvent具体代码如下

@Overridepublic boolean onTouchEvent(MotionEvent event) {if (getChildCount() == 0) {return false;}final int y = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:startTouch(event);break;case MotionEvent.ACTION_MOVE:if (mTouchMode == TOUCH_MODE_DOWN) {startScrollIfNeeded(y);} else if (mTouchMode == TOUCH_MODE_SCROLL) {scrollList(y);}break;case MotionEvent.ACTION_UP:break;default:endTouch();break;}return true;}


滚动的关键就在scrollList(y), 而startScrollIfNeeded(y);只是判断当前是否足够滚动的条件,也就是是否滚动超过一定距离。

/** * 控制ListView进行滚动 *  * @param y 当前触摸点Y轴的值 */private void scrollList(int y) { // scrollIfNeeded// 当前手指坐在位置与刚触摸到屏幕之间的距离// 也就是当前手指在屏幕上Y轴总移动位置int scrolledDistance = y - mTouchStartY;// 改变当前记录的ListView顶部位置mListTop = mListTopStart + scrolledDistance;// 关键,要想使相面的计算生效必须重新请求布局// 会触发当前onLayout方法,指定Item位置与绘制先关还是在onLayout中requestLayout();}

上面代码已经写了充分的注释,这里就不再过多的解释了。


三、填充整个ListView

    前一篇博文只是填充了一屏幕Item因为ListView不会滚动,所以并不需不要显示完整了,当前添加了滚动所以现在添加所有Item的支持。

先看下完整onLayout方法代码

@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);// 异常处理if (mAdapter == null) {return;}// 当前ListView没有任何子视图(Item),所以依次在从上向下填充子视图if (getChildCount() == 0) {mLastItemPosition = -1;// add and measurefillListDown(mListTop, 0);} else {final int offset = mListTop + mListTopOffset - getChildAt(0).getTop();// removefillList(offset);}// layout,添加测量完后,获取视图摆放位置positioinItems();// draw, 上面子视图都添加完了,重绘布局把子视图绘制出来吧invalidate();}


具体填充Item方法。

/** * ListView向上或者向下移动后需要向顶部或者底部添加视图 *  * @param offset */private void fillList(final int offset) {// 最后一个item的下边界值就是当前ListView的下边界值final int bottomEdge = getChildAt(getChildCount() - 1).getBottom();fillListDown(bottomEdge, offset);// 第一个Item的上边界值就是ListVie的上边界值final int topEdge = getChildAt(0).getTop();fillListUp(topEdge, offset);}/** * 与fillListDown相反方向添加 *  * @param topEdge 当前第一个子视图顶部边界值 * @param offset 显示区域偏移量 */private void fillListUp(int topEdge, int offset) {while (topEdge + offset > 0 && mFirstItemPosition > 0) {// 现在添加的视图时当前子视图后面,所以位置+1mLastItemPosition--;View newTopChild = mAdapter.getView(mFirstItemPosition, null, this);addAndMeasureChild(newTopChild, LAYOUT_MODE_ABOVE);int childHeight = newTopChild.getMeasuredHeight();topEdge -= childHeight;// 在顶部添加视图后,更新顶部偏移mListTopOffset -= childHeight;}}


四、源码下载


转载请注明出处:http://blog.csdn.net/love_world_/article/details/8743770




原创粉丝点击