viewAndroid自定义View

自定义View--View的measure过程

2016-08-24  本文已影响45人  heiheiwanne

窗口的顶级布局:包含了titlebar(标题栏)、content(内容android.R.id.content)
通过android.R.id.content获得内容布局的Parent层:

ViewGroup content = (ViewGroup)findViewById(android.R.id.content)  ;
View view = content.getChildAt(0);

View的measure过程

1.UNSPECIFIED
父容器不对Viewyou任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量的状态,一般属于系统内部多次Measure的情形,一般来说不需要关注此模式

2.EXACTLY
父容器已经检测出View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的的值,他对应于LayoutParams中的match_parent 和具体的数值这两种模式

3.AT_MOST
父容器指定了一个可用大小即SpecSize,View 的大小不能大于这个值具体是什么要看不同View的具体实现。他对应于LayoutParams中的wrap_content

parentSpecMode EXACTLY AT_MOST UNSPECIFIED
chlidLayoutParams
dp/px(固定数值) EXACTLY childSize EXACTLY childSize EXACTLY childSize
match_parent EXACTLY parentSize AT_MOST parentSize UNSPECIFIED 0
wrap_content AT_MOST parentSize AT_MOST parentSize UNSPECIFIED 0

从上边的表中可以看出View的match_parent 和 wrap_content 是一样的结果都是parent剩余的大小,这样跟我们的实际结果是不一样的,实际上在View这种情况先是进行了一定的处理的
具体代码是这样的:

public class mView extends View {
    public mView(Context context) {
        super(context);
    }

    private int mWidth = 0;
    private int mHeight = 0;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(mWidth, mHeight);
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(mWidth, heightSpecSize);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSpecSize, mHeight);
        }
    }
}

@Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
        if (hasWindowFocus) {
            int width = getMeasuredWidth();
            int height = getMeasuredHeight();
        }
    }
 @Override
    protected void onStart() {
        super.onStart();
        view.post(new Runnable() {
            @Override
            public void run() {
                int width = view.getMeasuredWidth();
                int height = view.getMeasuredHeight();
            }
        });
        
        Log.e(TAG, "onStart()");
    }
 ViewTreeObserver observer = view.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
            @SuppressWarnings("deprecation")
            @Override
            public void onGlobalLayout() {
                view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                int width = view.getMeasuredWidth();
                int height = view.getMeasuredHeight();
            }
        });
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
     int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
     view.measure(widthMeasureSpec, heightMeasureSpec);

注意到(1<<30)-1 ,通过分析MeasureSpec的实现可以知道,View的尺寸使用30位二进制表示也就是说最大是30个1(即2^30 -1 ),也就是(1<<30)-1,在最大化模式下,我们用View理论上能支持的最大值去构造MeasureSpec是合理的
+ 具体数值(dp/px)

 //比如宽/高 都是100px 如下measure
       int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
       int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
       view.measure(widthMeasureSpec,heightMeasureSpec);

错误用法:无法通过错误的MeasureSpec去得出合法的SpecMode,从而导致measure过程出错

int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec( -1, View.MeasureSpec.UNSPECIFIED);
        int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec( -1, View.MeasureSpec.UNSPECIFIED);
        view.measure(widthMeasureSpec, heightMeasureSpec);
view.measure(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
上一篇下一篇

猜你喜欢

热点阅读