深入源码Android ListView工作原理完全解析(下)

滑动加载更多数据

经历了两次 Layout 过程,虽说我们已经可以在 ListView 中看到内容了,然而关于 ListView 最神奇的部分我们却还没有接触到,因为目前 ListView 中只是加载并显示了第一屏的数据而已。比如说我们的 Adapter 当中有 1000 条数据,但是第一屏只显示了 10 条,ListView 中也只有 10 个子 View 而已,那么剩下的 990 是怎样工作并显示到界面上的呢?这就要看一下 ListView 滑动部分的源码了,因为我们是通过手指滑动来显示更多数据的。

由于滑动部分的机制是属于通用型的,即 ListView 和 GridView 都会使用同样的机制,因此这部分代码就肯定是写在 AbsListView 当中的了。那么监听触控事件是在 onTouchEvent() 方法当中进行的,我们就来看一下 AbsListView 中的这个方法:

@Override
public boolean onTouchEvent(MotionEvent ev) {
	if (!isEnabled()) {
		// A disabled view that is clickable still consumes the touch
		// events, it just doesn't respond to them.
		return isClickable() || isLongClickable();
	}
	final int action = ev.getAction();
	View v;
	int deltaY;
	if (mVelocityTracker == null) {
		mVelocityTracker = VelocityTracker.obtain();
	}
	mVelocityTracker.addMovement(ev);
	switch (action & MotionEvent.ACTION_MASK) {
	case MotionEvent.ACTION_DOWN: {
		mActivePointerId = ev.getPointerId(0);
		final int x = (int) ev.getX();
		final int y = (int) ev.getY();
		int motionPosition = pointToPosition(x, y);
		if (!mDataChanged) {
			if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)
					&& (getAdapter().isEnabled(motionPosition))) {
				// User clicked on an actual view (and was not stopping a
				// fling). It might be a
				// click or a scroll. Assume it is a click until proven
				// otherwise
				mTouchMode = TOUCH_MODE_DOWN;
				// FIXME Debounce
				if (mPendingCheckForTap == null) {
					mPendingCheckForTap = new CheckForTap();
				}
				postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
			} else {
				if (ev.getEdgeFlags() != 0 && motionPosition < 0) {
					// If we couldn't find a view to click on, but the down
					// event was touching
					// the edge, we will bail out and try again. This allows
					// the edge correcting
					// code in ViewRoot to try to find a nearby view to
					// select
					return false;
				}

				if (mTouchMode == TOUCH_MODE_FLING) {
					// Stopped a fling. It is a scroll.
					createScrollingCache();
					mTouchMode = TOUCH_MODE_SCROLL;
					mMotionCorrection = 0;
					motionPosition = findMotionRow(y);
					reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
				}
			}
		}
		if (motionPosition >= 0) {
			// Remember where the motion event started
			v = getChildAt(motionPosition - mFirstPosition);
			mMotionViewOriginalTop = v.getTop();
		}
		mMotionX = x;
		mMotionY = y;
		mMotionPosition = motionPosition;
		mLastY = Integer.MIN_VALUE;
		break;
	}
	case MotionEvent.ACTION_MOVE: {
		final int pointerIndex = ev.findPointerIndex(mActivePointerId);
		final int y = (int) ev.getY(pointerIndex);
		deltaY = y - mMotionY;
		switch (mTouchMode) {
		case TOUCH_MODE_DOWN:
		case TOUCH_MODE_TAP:
		case TOUCH_MODE_DONE_WAITING:
			// Check if we have moved far enough that it looks more like a
			// scroll than a tap
			startScrollIfNeeded(deltaY);
			break;
		case TOUCH_MODE_SCROLL:
			if (PROFILE_SCROLLING) {
				if (!mScrollProfilingStarted) {
					Debug.startMethodTracing("AbsListViewScroll");
					mScrollProfilingStarted = true;
				}
			}
			if (y != mLastY) {
				deltaY -= mMotionCorrection;
				int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
				// No need to do all this work if we're not going to move
				// anyway
				boolean atEdge = false;
				if (incrementalDeltaY != 0) {
					atEdge = trackMotionScroll(deltaY, incrementalDeltaY);
				}
				// Check to see if we have bumped into the scroll limit
				if (atEdge && getChildCount() > 0) {
					// Treat this like we're starting a new scroll from the
					// current
					// position. This will let the user start scrolling back
					// into
					// content immediately rather than needing to scroll
					// back to the
					// point where they hit the limit first.
					int motionPosition = findMotionRow(y);
					if (motionPosition >= 0) {
						final Vi
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值