概述
经过上一篇Fragment源码的分析,我发现想要完全弄懂源码中的每一个点是不可能的,而且会让自己陷入细枝末节无法自拔,所以我认为在整体上先有一个感性认识,细节问题遇到了再去有针对性的解决是一个比较好的阅读源码的姿势。
经过思考,我觉得还是像Fragment一样从API的调用来分析ViewPager的运行过程 会比较清晰。
平常我们使用到ViewPager,一般会调用下面几个方法,如果是配合Fragment的话,界面就能显示在屏幕上了。
mViewPager.setAdapter(new HomeAdapter(getXXXManager(), mFragments));
mViewPager.setCurrentItem(2);
ViewPager就为一个ViewGroup,和其他所有View一样,会在Activity(假设是在Activity的布局中)的onCreate() 回调的 setContentView() 中通过反射被实例化作为DOM树的一个节点,这里会调用其构造器。接着,我们会在Activity的onCreate() 中调用ViewPager#setAdapter() 和 ViewPager#setCurrentItem() , 在onResume() 回调之后由ViewRootImpl发起绘制流程,依次会回调到ViewPager的onMeasure() 、onLayout() 、onDraw() ,ViewPager就可以显示在屏幕上了。之后ViewPager的滑动就和onInterceptTouchEvent() 、onTouchEvent() 回调相关。我们按顺序一个一个来看。
关注一下成员
有一个静态内部类代表了页面的状态,我们需要关注一下。
//ViewPager.java
static class ItemInfo {
Object object;
int position;
boolean scrolling;
//占屏比,0~1
float widthFactor;
//页面偏移量
float offset;
}
构造器
都调用了initViewPager() 方法
//ViewPager.java
public ViewPager(Context context) {
super(context);
initViewPager();
}
初始化了一些变量,看到新建了一个Scroller对象,这个对象一般是用来做弹性滑动的,所以可能和后面的滑动相关。
//ViewPager.java
void initViewPager() {
...
mScroller = new Scroller(context, sInterpolator);
...
if (ViewCompat.getImportantForAccessibility(this)
== ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
ViewCompat.setImportantForAccessibility(this,
ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
...
}
setAdapter()
在进入到ViewPager的绘制流程之前,我们会在Activity的例如onCreate()回调中调用ViewPager的这个方法。这个方法做了如下几件事,重要细节备注在源码中:
1.如果原来设置了Adapter,清除相关信息。
2.设置新的Adapter,请求开始绘制。
3.回调相关函数。
//ViewPager.java
public void setAdapter(PagerAdapter adapter) {
if (mAdapter != null) {
//清除监听者,是这个ViewPager的一个内部类
mAdapter.setViewPagerObserver(null);
//回调
mAdapter.startUpdate(this);
//清除页面信息
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
mAdapter.destroyItem(this, ii.position, ii.object);
}
//回调
mAdapter.finishUpdate(this);
//清除mItems
mItems.clear();
removeNonDecorViews();
//设置当前位置
mCurItem = 0;
//滑动到
scrollTo(0, 0);
}
final PagerAdapter oldAdapter = mAdapter;
mAdapter = adapter;
mExpectedAdapterCount = 0;
//配置新的信息
if (mAdapter != null) {
if (mObserver == null) {
//是ViewPager的一个内部类
mObserver = new PagerObserver();
}
mAdapter.setViewPagerObserver(mObserver);
mPopulatePending = false;
final boolean wasFirstLayout = mFirstLayout;
mFirstLayout = true;
mExpectedAdapterCount = mAdapter.getCount();
//如果有需要恢复的页面
if (mRestoredCurItem >= 0) {
mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
setCurrentItemInternal(mRestoredCurItem, false, true);
mRestoredCurItem = -1;
mRestoredAdapterState = null;
mRestoredClassLoader = null;
} else if (!wasFirstLayout) {
//重要函数,但这里调用不到,因为我们这里是第一次布局。
populate();
} else {
//绘制
requestLayout();
}
}
// Dispat