相关知识: 1、View的onMeasure等的加载过程 ViewRootImpl 调用perfomTravsals中的performMeasure,再调用performLayout
//这里就是线性布局比相对布局性能好的原因 //相对布局会调用两次,线性布局会调用一次 int width = host.getMeasuredWidth(); int height = host.getMeasuredHeight(); boolean measureAgain = false; if (lp.horizontalWeight > 0.0f) { width += (int) ((mWidth - width) * lp.horizontalWeight); childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); measureAgain = true; } if (lp.verticalWeight > 0.0f) { height += (int) ((mHeight - height) * lp.verticalWeight); childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); measureAgain = true; } if (measureAgain) { if (DEBUG_LAYOUT) Log.v(mTag, "And hey let's measure once more: width=" + width + " height=" + height); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); }performMeasure再调用mView.measure(childWidthMeasureSpec, childHeightMeasureSpec)方法实现view的measure方法。
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure"); try { mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }2、xml布局文件的加载流程 (1)使用LayoutInflater的Inflate方法,获得一个xml解析器
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) { final Resources res = getContext().getResources(); if (DEBUG) { Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" (" + Integer.toHexString(resource) + ")"); } final XmlResourceParser parser = res.getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { parser.close(); } }(2)使用xml解析器,解析xml文件
// Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty }(3)为View创建Tag
// Temp is the root view that was found in the xml final View temp = createViewFromTag(root, name, inflaterContext, attrs); ViewGroup.LayoutParams params = null; if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } // Create layout params that match root, if supplied //把所有属性进行传递 params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) //设置属性 temp.setLayoutParams(params); }实现自定义百分比布局的思路, (1)自定义实现ViewGroup的LayoutParams。
public static class LayoutParamsSelf extends RelativeLayout.LayoutParams{ private float widthPercent; private float heightPercent; public float getWidthPercent() { return widthPercent; } public float getHeightPercent() { return heightPercent; } public void setWidthPercent(float widthPercent) { this.widthPercent = widthPercent; } public void setHeightPercent(float heightPercent) { this.heightPercent = heightPercent; } public LayoutParamsSelf(Context c, AttributeSet attrs) { super(c, attrs); TypedArray array=c.obtainStyledAttributes(attrs,R.styleable.PercentLayout); widthPercent=array.getFloat(R.styleable.PercentLayout_layout_widthPercent,widthPercent); heightPercent=array.getFloat(R.styleable.PercentLayout_layout_heightPercent,heightPercent); array.recycle(); } public LayoutParamsSelf(int width, int height) { super(width, height); } public LayoutParamsSelf(MarginLayoutParams source) { super(source); } public LayoutParamsSelf(ViewGroup.LayoutParams source) { super(source); } } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParamsSelf(getContext(),attrs); }(2)在onMeasure测量出子控件的宽和高,进行改变
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.e("TAG","onMeasuer"); int width= View.MeasureSpec.getSize(widthMeasureSpec); int height=View.MeasureSpec.getSize(heightMeasureSpec); int count =getChildCount(); for (int i=0;i<count;i++){ View childAt=getChildAt(i); ViewGroup.LayoutParams layoutParams=childAt.getLayoutParams(); float widthPercent=0; float heightPercent=0; if(layoutParams instanceof PercentLayout.LayoutParamsSelf){ widthPercent=((PercentLayout.LayoutParamsSelf)layoutParams).getWidthPercent(); heightPercent=((PercentLayout.LayoutParamsSelf)layoutParams).getHeightPercent(); } if(widthPercent!=0){ layoutParams.width=(int)(width*widthPercent); } if(heightPercent!=0){ layoutParams.height=(int)(height*heightPercent); } } Log.e("TAG","widthMeasureSpec "+widthMeasureSpec+" heightMeasureSpec"+heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec); }构造方法及继承Relativelayout
public PercentLayout(Context context) { this(context,null); } public PercentLayout(Context context, AttributeSet attrs) { this(context, attrs,0); } public PercentLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); }