写在前面
做安卓也有一定时间了,虽然常用控件都已大致掌握,然而随着 Android N 的发布,不自觉的愈发焦虑起来。说来惭愧,Android L 的 Material Design 库里的许多控件都还没用过,照这样下去迟早要被新技术所淘汰。那该怎么办呢,偶然间我看到一篇博文如此说到:“不要觉得 android 里边控件繁杂多样,官方或第三方新控件层出不穷,其实真正的控件就只有两个View
和ViewGroup
。一旦有了它们的基础,不管来什么新控件,TabLayout
也好,CoordinatorLayout
也罢,花上一下午翻翻源码基本就掌握了(不仅仅是会用而已)。”
我明白了:新技术的精华还在新技术之外。抛开追寻新技术的浮躁,我决定补一补基础,这也是我写这篇文章的初衷。希望它能开一个好头,勉励自己沉下心来,read the fucking source code!
知识点
之所以选择 ViewPager 是因为它常常用到,大家对它足够熟悉。同时它有些难度,却又是自定义View的官方经典例子,涵盖了不少知识点:
- PagerAdapter、DataSetObserver 与观察者模式
- View 的生命周期(measure -> layout -> draw)
- View 的事件分发(滑动冲突的解决)
- View 滑动的工具类 (Scroller、VelocityTracker 等)
- …
阅读下文需要您已经有 ViewPager 、PagerAdapter 的使用经验,同时对 View 的绘制和事件分发流程有一定的了解。由于篇幅有限,本文只写到第一点;后几点回以续章的形式呈现。
源码分析
Adapter、DataSetObserver 与观察者模式
我们使用 ViewPager
,通常需要定义一个PagerAdapter
,然后setAdapter()
,用法上和ListView
很像。如图:
我们看到,PagerAdapter
持有数据集DataSetObservable
,同时包含一些回调。
setAdapter()
那么很自然的,我们从ViewPager
的setAdapter
开始分析把。
public void setAdapter(PagerAdapter adapter) {
if (mAdapter != null) { // 1: 清空旧的 Adapter, 做一些初始化处理
mAdapter.unregisterDataSetObserver(mObserver);
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.clear();
removeNonDecorViews();
mCurItem = 0;
scrollTo(0, 0);
}
// 2: 更新 mAdapter 字段
final PagerAdapter oldAdapter = mAdapter;
mAdapter = adapter;
mExpectedAdapterCount = 0;
// 3: 给 mAdapter 添加数据 mObserver,恢复状态
if (mAdap