您的位置:首页 > 移动开发 > Android开发

Android View绘制13问13答

2016-02-04 16:06 507 查看
1.View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view?

答:从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程。draw流程结束以后就可以在屏幕上看到view了。

2.view的测量宽高和实际宽高有区别吗?

答:基本上百分之99的情况下都是可以认为没有区别的。有两种情况,有区别。第一种 就是有的时候会因为某些原因 view会多次测量,那第一次测量的宽高 肯定和最后实际的宽高 是不一定相等的,但是在这种情况下

最后一次测量的宽高和实际宽高是一致的。此外,实际宽高是在layout流程里确定的,我们可以在layout流程里 将实际宽高写死 写成硬编码,这样测量的宽高和实际宽高就肯定不一样了,虽然这么做没有意义 而且也不好。

3.view的measureSpec 由谁决定?顶级view呢?

答:由view自己的layoutparams和父容器 一起决定自己的measureSpec。一旦确定了spec,onMeasure中就可以确定view的宽高了。

顶级view就稍微特殊一点,对于decorView的测量在ViewRootImpl的源码里。

package com.example.administrator.motioneventtest;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

/**
* Created by Administrator on 2016/2/4.
*/
//这里我们只处理了padding的状态 没有处理margin的状态,子view的margin 对measure和layout的影响
//就留给读者自己完成了
public class CustomHorizontalLayout extends ViewGroup {

//设置默认的控件最小是多少 这里不提供自定义属性了 写死在代码里 你们可以自行拓展
final int minHeight = 0;
final int minWidth = 0;

public CustomHorizontalLayout(Context context) {
super(context);
}

public CustomHorizontalLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}

public CustomHorizontalLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int measureWidth = 0;
int measureHeight = 0;
final int childCount = getChildCount();
measureChildren(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
final View childView = getChildAt(0);
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
//没有子控件 时 我们的宽高要作特殊处理
if (childCount == 0) {
//当没有子控件时,如果长宽有一个为wrap 那么就让这个控件以最小的形式展现
//这里我们最小设置为0
if (widthSpecMode == MeasureSpec.AT_MOST || heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(minWidth, minHeight);
} else {
//否则根据我们的layout属性来
setMeasuredDimension(getLayoutParams().width, getLayoutParams().height);
}

} else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
measureWidth = childView.getMeasuredWidth() * childCount;
measureHeight = childView.getMeasuredHeight();
setMeasuredDimension(paddingLeft + measureWidth + paddingRight, paddingTop + measureHeight + paddingBottom);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
measureHeight = childView.getMeasuredHeight();
setMeasuredDimension(paddingLeft + paddingRight + widthSpecSize, paddingTop + paddingBottom + measureHeight);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
measureWidth = childView.getMeasuredWidth() * childCount;
setMeasuredDimension(paddingLeft + paddingRight + measureWidth, paddingTop + paddingBottom + heightSpecSize);
}
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
//左边初始位置为0
int childLeft = 0 + paddingLeft;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View childView = getChildAt(i);
if (childView.getVisibility() != View.GONE) {
final int childWidth = childView.getMeasuredWidth();
childView.layout(childLeft, 0 + paddingTop, childLeft + childWidth, paddingTop + childView.getMeasuredHeight());
childLeft += childWidth;
}
}
}
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: