Android应用制作指导

Android应用制作指导

android的UI布局过程setContentView(R.layout.activity_main);
初识UI的布局起始过程Activity.java的getWindow()拿到的就是Window的实现类PhoneWindow。

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecoricationBar();
}

measure、layout、draw的三个执行流程View.java的源码在View.java的源码中有三个方法:

1. measure:测量,测量自己有多大。如果是ViewGroup的话会同时测量里面子控件的大小。
2. layout:摆放里面的子控件。
3. draw:绘制View。

View.java类的源码:

1. view 的 requestLayout() 方法开始,递归地不断往上找父容器,最终找到 DecorView(是WindowPhone的内部类,继承自帧布局)。
PhoneWindow 源码:com.android.internal.policy.impl@Overridepublic void setContentView(int layoutResID){
    // Note:FETURE_CONTENT_TRANSLATION可能会在安装window的decor,when the theme attributes and likes are crystallized.
    // Don't check the feature before this happens.
    if (mContentParent == null) {
        installDecor();
    } else {
        // 二&...
        ...
    }
	// 这个layotResID,就是用户在activity中传进来的布局idmLayotInflater.inflate(layoutResID,mContentParent);
    // 六}
    installDecor();
    private void installDecor(){
        if(mDecor == null){
            mDecor = generateDecor();
            mDecor.setDescendantFocusingOrder(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if(!mInvalidatePanelMenuPosted && mInvalidatePanel MenFeatures !=]){
                mDecor.postOnAnimation(mInvalidatePanelMenRunnable);
            }
        }
        if(mContentParent == null){
            mContentParent = generateLayot(mDecor);
            // 四}
            protected ViewGroup generateLayot(DecorView decor){
                // 五、
                View in = mLayotInflater.inflate(layotResorce, null);
                decor.addView(in, newViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
                mContentRoot = (ViewGroup)in;
                // 六}
            }
        }

执行了DecorView的ViewRootImpl类的performTranversal()方法。

performTranversal()方法如下:

4. performMeasure()方法,执行该方法进行测量

ViewGroup.java源码一、measure的过程如何去合理的测量一颗view树?

如果 View 和 View都是直接指定的宽高,我还要测量吗?

正是因为谷歌设计的自适应尺寸机制(比如Match_parent,wrap_content),造成了宽高不确定,所以就需要进程测量。

measure过程会遍历整颗View树,然后依次测量每一个View的真实的尺寸。

MeasreSpec:测量规格在xml文件中的width和height的match_parent和wrap_content或者具体的值。
在代码中具体体现的都是个位的int值。

所以通常拿这个int值得前位作为测量模式,后面位当做值。
mode:EXCTLY:精确的。比如给了一个确定的值1dp和Match_parent属于这种。
T_MOST:根据父容器当前的大小,结合你指定的尺寸参考值来考你应该是多大尺寸,需要计算(wrap_content就是属于这种)UNSPECIFIED:值未指定的意思。

根据当前的情况,结合你指定的尺寸参考值来考虑,在不超过父容器给你限定的值的前提下,来测量你的一个恰好的内容尺寸。
用的比较少,一般见于 ScrollView,ListView(大小不确定,同时大小还是变的。会通过多次测量才能真正决定好宽高)

vale:宽高的值performTranversal(){
	// skhosthowbigitwantstobeperformMeasure(childWidthMeasreSpec,childHeight MeasreSpec);
	performLayout(lp,desiredWindowWidth,desiredWindowHeight);
	performDraw();
}

private void performMeasure(int childWidthMeasreSpec,int childHeightMeasreSpec){
    Trace.traceBegin(Trace.TRACE_TAG_VIEW,"measure");
    try{
        mView.measure(childWidthMeasreSpec,childHeightMeasreSpec);
    }finally{
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}
经过大量测量以后,最终确定自己的宽高,需要再调用:setMeasuredDimension(w,h)。

写自定义控件的时候,我们要去获得自己的宽高来进行一些计算。

必须先经过measure,才能获得到宽高---不是getWidth(),而是getMeasureWidth()。

也就是当我们重写onMeasure的时候,我们需要在里面调用child.measure()才能获取child的宽高。

android的UI布局过程Activity.java的getWindow()拿到的是Window的实现类PhoneWindow measure、layout、draw的三个执行流程View.java源码ViewGroup.java源码一、measure的过程

author