本篇主要分析ViewPager动起来是怎么处理的
//从方法名称看能知道,已知position的位置,滑动到相应的位置,第二个方法为
//是否是平滑滑动,第三个成为是滑动的速率吧,第四个参数是否回调
//onPageSelected方法
private void scrollToItem(int item, boolean smoothScroll, int velocity,
boolean dispatchSelected) {
//根据传入的Position,从mItems中获取ItemInfo
final ItemInfo curInfo = infoForPosition(item);
int destX = 0;
if (curInfo != null) {
//得到宽
final int width = getClientWidth();
//得到X需要移动的位置
destX = (int) (width * Math.max(mFirstOffset,
Math.min(curInfo.offset, mLastOffset)));
}
//需要平滑滑动
if (smoothScroll) {
//开始平滑滚动
smoothScrollTo(destX, 0, velocity);
if (dispatchSelected) {
//对onPageSelected方法进行回调
dispatchOnPageSelected(item);
}
} else {
if (dispatchSelected) {
//回调onPageSelected方法
dispatchOnPageSelected(item);
}
//滚动完成的一些处理
completeScroll(false);
//如果没调用平滑滚动,就将ViewPager直接滚动到传入的界面
scrollTo(destX, 0);
//回调pageScrolled方法
pageScrolled(destX);
}
}
实现平滑滚动,该方法主要是求出来当前x的位置,需要移动的x位置,当前y的位置,需要移动到y的位置
通过startScroll和重写computeScroll方法,实现的缓慢滚动的效果
void smoothScrollTo(int x, int y, int velocity) {
// ViewPager如果没有View,清除缓存
if (getChildCount() == 0) {
// Nothing to do.
setScrollingCacheEnabled(false);
return;
}
int sx;
//判断上一次滑动的动画是否结束
boolean wasScrolling = (mScroller != null) && !mScroller.isFinished();
//从代码来看,如果为正在运动的scroller,当前位置为getCurrX
//否则为getScrollX
if (wasScrolling) {
//判断当前是滚动了,如果为真。sx为计算的当前位置,否则为初始坐标
sx = mIsScrollStarted ? mScroller.getCurrX() : mScroller.getStartX();
// And abort the current scrolling.
//将滚动动画停止
mScroller.abortAnimation();
setScrollingCacheEnabled(false);
} else {
sx = getScrollX();
}
//假如我现在在第一个界面,只显示了一半
//我调用smoothScrollTo(int x, int y, int velocity) 传入1080(如果getScrollX为1080即为第二个页面),0,0
//算出y滑动的距离
int sy = getScrollY();
//算出需要滑动的X距离
int dx = x - sx;
//算出需要滑动的Y距离
int dy = y - sy;
//如果dx和dy都等于0,证明,滑动已经结束
if (dx == 0 && dy == 0) {
completeScroll(false);
populate();
//设置状态为SCROLL_STATE_IDLE
setScrollState(SCROLL_STATE_IDLE);
return;
}
//开启缓存
setScrollingCacheEnabled(true);
//设置状态为SCROLL_STATE_SETTLING
setScrollState(SCROLL_STATE_SETTLING);
//下面的代码就是通过已经滚动的比例计算,计算剩下需要滚动内容所需要的时间
final int width = getClientWidth();
final int halfWidth = width / 2;
final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);
final float distance = halfWidth + halfWidth
* distanceInfluenceForSnapDuration(distanceRatio);
int duration;
velocity = Math.abs(velocity);
if (velocity > 0) {
duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
} else {
final float pageWidth = width * mAdapter.getPageWidth(mCurItem);
final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin);
duration = (int) ((pageDelta + 1) * 100);
}
duration = Math.min(duration, MAX_SETTLE_DURATION);
// Reset the "scroll started" flag. It will be flipped to true in all places
// where we call computeScrollOffset().
//这个方法设置为flase,但是却在每一个调用
//computeScrollOffset方法之前只为true
mIsScrollStarted = false;
//开启平滑滚动
mScroller.startScroll(sx, sy, dx, dy, duration);
//不断进行绘制,会回调computeScroll方法
ViewCompat.postInvalidateOnAnimation(this);
}
当调用postInvalidateOnAnimation会不断的绘制视图,从而实现平滑滚动
@Override
public void computeScroll() {
//当前正在滚动
mIsScrollStarted = true;
//如果当前动画没有执行完
if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
//得到滑动的位置,可以理解成旧的位置
int oldX = getScrollX();
int