自定义ViewGroup中onLayout()确定子View位置和大小

来源:互联网 发布:晨曦计价软件官网 编辑:程序博客网 时间:2024/05/17 08:58

先来看一个很简单的例子,一个继承至ViewGroup的自定义控件容器

public class MyViewGroup extends ViewGroup {    public MyViewGroup(Context context) {        super(context);    }    public MyViewGroup(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {    }}

然后再XML中添加一个Button,结果不管在XML视图中还是运行起来都看不到button。大家都知道要在MyViewGroup中重写onLayout()方法来确定子view布局位置和大小。
我们在ViewGroup中找到onLayout()方法,发现他是一个抽象方法,你必须重写他,否则就像上面看不到子view。

 /**     * {@inheritDoc}     */    @Override    protected abstract void onLayout(boolean changed,            int l, int t, int r, int b);

那究竟在onLayout()中怎么去确定子View的位置?
回到上面那个例子,如果我们把MyViewGroup换成我们常见的RelativeLayout,想都不用想妥妥能看到Button的对吧,那我们就去看看RelativeLayout的onLayout()做了什么事情,代码如下:

 @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        final int count = getChildCount();        for (int i = 0; i < count; i++) {            View child = getChildAt(i);            if (child.getVisibility() != GONE) {                RelativeLayout.LayoutParams st =                        (RelativeLayout.LayoutParams) child.getLayoutParams();                child.layout(st.mLeft, st.mTop, st.mRight, st.mBottom);            }        }    }

这段代码的核心就是child.layout(……)这个方法了,这个方法直接确定子view显示位置。这个方法需要传递四个参数:layout(int l, int t, int r, int b)。四个参数什么意思?先copy下网上的一张图(摘自http://blog.csdn.net/dmk877/article/details/49632959):
这里写图片描述
第一个参数l,即left对应图上的mLeft,以此类推,所以很清楚知道了四个参数分别是子view在父控件坐标系中左边框X坐标,右边框X坐标,上边框Y坐标,下边框Y坐标。为什么是这四个值?仔细想想就知道,只要这四个值就能确定子view的位置和大小了。
l和t好办,我们可以自己定义数值,设置边距。而r跟b其实就是子view的宽高了,子view宽高其实是可以获取的。首先在onMeasure()方法中测量子view的大小。

   @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        measureChildren(widthMeasureSpec, heightMeasureSpec);    }

然后我们就可以获取子view的宽高了:

 int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight();

那现在就知道怎么修改我们的MyViewGroup了吧,改后代码是这样的:

  @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        measureChildren(widthMeasureSpec, heightMeasureSpec);    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        final int count = getChildCount();        for (int i = 0; i < count; i++) {            View child = getChildAt(i);            int childWidth = child.getMeasuredWidth();            int childHeight = child.getMeasuredHeight();            if (child.getVisibility() != GONE) {                child.layout(100, 200, childWidth+100, childHeight+200);            }        }    }

测试下,嗯不负众望,子view出来了:
这里写图片描述

2 0
原创粉丝点击