标签:
private void performTraversals() {
......
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); ...... mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight()); ...... mView.draw(canvas); ...... }
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int maxHeight = 0;
int maxWidth = 0; int childState = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i);
// 遍历自己的子View,只要不是GONE的都会参与测量
if (mMeasureAllChildren || child.getVisibility() != GONE) {
//....
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
maxWidth = Math.max(maxWidth, child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
maxHeight = Math.max(maxHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); //.... }
} //....
setMeasuredDimension(
resolveSizeAndState(maxWidth, widthMeasureSpec, childState), resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT) );
//....
}
|
protected void measureChildWithMargins(View child,
int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) child.getLayoutParams(); // 根据父View的测量规格、父 View自己的Padding、子 View的Margin和已经用掉的空间大小( widthUsed),就能算出子View的 MeasureSpec,具体计算过程要看getChildMeasureSpec方法 int paddingWitdth = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed; int paddingHeight = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed; final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,paddingWitdth, lp. width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,paddingHeight, lp. height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }
|
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
int specMode = MeasureSpec.getMode(spec); //获得父 View给的mode int specSize = MeasureSpec.getSize(spec); //获得父 View给的大小 // 父View给的大小 -自己的Padding+子 View的Margin,得到值才是子 View的大小。 int size = Math.max( 0, specSize - padding); int resultSize = 0; //初始化值,最后通过这个两个值生成子 View的MeasureSpec int resultMode = 0; //初始化值,最后通过这个两个值生成子 View的MeasureSpec switch (specMode) {}//这里具体的switch case省略,逻辑与表[1]是一样的
//根据上面逻辑条件获取的 mode和size构建 MeasureSpec对象。
return MeasureSpec.makeMeasureSpec(resultSize, resultMode); }
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredWidth = getDefaultSize (getSuggestedMinimumWidth() , widthMeasureSpec ); int measuredHeight = getDefaultSize (getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(measuredWidth,measuredHeight); }
|
[1]
public static int getDefaultSize(int size, int measureSpec) {
int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: //表示该View的大小父视图未定,设置为默认值 result = size; break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } return result; }
|
[2]
protected int getSuggestedMinimumWidth() {
return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); }
|
(下)父View给的MeasureSpec
(右)子View的LayoutParams
(内容)要给子View的结果MeasureSpec
|
size | match_parent | wrap_content |
EXACTLY |
LayoutParams.size(居然是听子View的!但是可能无法全部显示)
EXACTLY
|
MeasureSpec.size
EXACTLY
|
MeasureSpec.size
AT_MOST(也是不确定,需要到子View那儿去之后再根据具体情况计算)
|
AT_MOST |
LayoutParams.size
EXACTLY
|
MeasureSpec.size
AT_MOST
|
MeasureSpec.size
AT_MOST
|
UNSPECIFIED |
LayoutParams.size
EXACTLY
|
0(一旦没有任何要求和约束,size的值就没有任何意义了,所以一般都直接设置成0)
UNSPECIFIED
|
0
UNSPECIFIED
|
private void performTraversals() {
......
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); ......
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
......
}
|
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
int measureSpec; switch (rootDimension) { case ViewGroup.LayoutParams.MATCH_PARENT: measureSpec = MeasureSpec.makeMeasureSpec(windowSize,MeasureSpec.EXACTLY); break; ...... } return measureSpec; }
|
private void performTraversals() {
......
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); ...... mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight()); ...... mView.draw(canvas); ...... }
|
public final void layout(int l, int t, int r, int b) {
if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) { if (mTransition != null) { mTransition.layoutChange(this); } super.layout(l, t, r, b); } else { mLayoutCalledWhileSuppressed = true; } }
|
public final void layout(int l, int t, int r, int b) {
.....
boolean changed = setFrame(l, t, r, b);
// 判断View的位置是否发生过变化,看有必要进行重新 layout吗 if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) { if (ViewDebug.TRACE_HIERARCHY) { ViewDebug.trace(this, ViewDebug.HierarchyTraceType. ON_LAYOUT); }
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~LAYOUT_REQUIRED; } mPrivateFlags &= ~FORCE_LAYOUT; ..... }
|
int childCount = getChildCount() ;
for(int i= 0 ;i< childCount ;i ++){ View child = getChildAt(i) ; child.layout(l, t, r, b) ; }
|
public void draw(Canvas canvas) {
... /* * Draw traversal performs several drawing steps which must be executed * in the appropriate order: * * 1. Draw the background * 2. If necessary, save the canvas‘ layers to prepare for fading * 3. Draw view‘s content * 4. Draw children * 5. If necessary, draw the fading edges and restore layers * 6. Draw decorations (scrollbars for instance) */ // Step 1, draw the background, if needed ... background.draw(canvas); ... // skip step 2 & 5 if possible (common case) ... // Step 2, save the canvas‘ layers ... if (solidColor == 0) { final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; if (drawTop) { canvas.saveLayer(left, top, right, top + length, null, flags); } ... // Step 3, draw the content if (!dirtyOpaque) onDraw(canvas); // Step 4, draw the children dispatchDraw(canvas); // Step 5, draw the fade effect and restore layers if (drawTop) { matrix.setScale(1, fadeHeight * topFadeStrength); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); canvas.drawRect(left, top, right, top + length, p); } ... // Step 6, draw decorations (scrollbars) onDrawScrollBars(canvas); } } |
private void drawBackground(Canvas canvas) {
Drawable final Drawable background = mBackground; ...... //mRight - mLeft, mBottom - mTop layout确定的四个点来设置背景的绘制区域 if (mBackgroundSizeChanged) { background.setBounds(0, 0, mRight - mLeft, mBottom - mTop); mBackgroundSizeChanged = false; rebuildOutline(); } ...... //调用Drawable的draw() 把背景图片画到画布上 background.draw(canvas); ...... } |
@Override
protected void dispatchDraw(Canvas canvas) { ... if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) { for (int i = 0; i < count; i++) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { more |= drawChild(canvas, child, drawingTime); } } } else { for (int i = 0; i < count; i++) { final View child = children[getChildDrawingOrder(count, i)]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { more |= drawChild(canvas, child, drawingTime); } } } ...... } |
4、第6步 对View的滚动条进行绘制
不是重点,知道有这东西就行,onDrawScrollBars 的一句注释 :Request the drawing of the horizontal and the vertical scrollbar. The scrollbars are painted only if they have been awakened first.
标签:
原文地址:http://www.cnblogs.com/bellkosmos/p/5937224.html