看一点记录一点,虽然网上很多大佬都有记录,但还是想自己学完记录下
ViewPager继承自ViewGroup,先从onMeasure、onLayout、onDraw开始看起
onMeasure
主要做了这几件事:
- 对整个ViewPager的大小进行设置。设置的大小为父类传递过来的大小,也就是剩余的空间,对这个不理解的可以看博主另一篇文章Android自定义时间轴
- 测量DecorView,并对其设置大小。使用ViewPager.DecorView注释的视图被视为ViewPager“装饰”的一部分。具体可以看博主另一篇文章PagerTitleStrip使用
- 测量Adapter的所有View,也就是每个Item,并设置其大小。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//设置ViewPager的大小,设置的大小为父类传递的剩余空间
setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
getDefaultSize(0, heightMeasureSpec));
final int measuredWidth = getMeasuredWidth();
final int maxGutterSize = measuredWidth / 10;
mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize);
// Children are just made to fill our space.
int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight();
int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
/*
* Make sure all children have been properly measured. Decor views first.
* Right now we cheat and make this less complicated by assuming decor
* views won't intersect. We will pin to edges based on gravity.
*/
//开始设置DecorView的大小
int size = getChildCount();
for (int i = 0; i < size; ++i) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp != null && lp.isDecor) {
//判断是不是设置了Gravity.LEFT || hgrav == Gravity.RIGHT
final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
//判断是不是设置了Gravity.TOP || vgrav == Gravity.BOTTOM
final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
int widthMode = MeasureSpec.AT_MOST;
int heightMode = MeasureSpec.AT_MOST;
boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT;
if (consumeVertical) {
widthMode = MeasureSpec.EXACTLY;
} else if (consumeHorizontal) {
heightMode = MeasureSpec.EXACTLY;
}
int widthSize = childWidthSize;
int heightSize = childHeightSize;
if (lp.width != LayoutParams.WRAP_CONTENT) {
widthMode = MeasureSpec.EXACTLY;
if (lp.width != LayoutParams.MATCH_PARENT) {
widthSize = lp.width;
}
}
if (lp.height != LayoutParams.WRAP_CONTENT) {
heightMode = MeasureSpec.EXACTLY;
if (lp.height != LayoutParams.MATCH_PARENT) {
heightSize = lp.height;
}
}
//对DecorView进行设置长和宽
final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
child.measure(widthSpec, heightSpec);
if (consumeVertical) {
//ViewPager剩余的高(也就是每个Item的高)是减掉DecorView的高
childHeightSize -= child.getMeasuredHeight();
} else if (consumeHorizontal) {
//ViewPager剩余的宽(也就是每个Item的宽)是减掉DecorView的宽
childWidthSize -= child.getMeasuredWidth();
}
}
}
}
//ViewPager宽度剩余的MeasureSpec,没用上
mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
//ViewPager高度剩余的MeasureSpec
mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY);
// Make sure we have created all fragments that we need to have shown.
mInLayout = true;
populate();
mInLayout = false;
// Page views next.
//开始设置每个Item的宽高
size = getChildCount();
for (int i = 0; i < size; ++i) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
if (DEBUG) {
Log.v(TAG, "Measuring #" + i + " " + child + ": " + mChildWidthMeasureSpec);
}
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp == null || !lp.isDecor) {
//生成每个Item的宽的MeasureSpec
final int widthSpec = MeasureSpec.makeMeasureSpec(
(int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY);
//对每个Item的宽高进行设置
child.measure(widthSpec, mChildHeightMeasureSpec);
}