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

相关知识:
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);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值