Android中实现自定义百分比布局

    xiaoxiao2021-03-25  174

    相关知识: 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); }
    转载请注明原文地址: https://ju.6miu.com/read-1823.html

    最新回复(0)