自定义布局之树形布局(四):子控件摆放

上一篇以水平方向为例讲解了树形布局的宽高测量,本篇讲解子控件的摆放。水平树的摆放原理和竖直方向的摆放原理是一样的,这里就继续顺着水平树的思路进行。

重写onLayout方法

不同于一般的自定义控件,布局类控件除了考虑自身的情况,还得考虑到各个子控件。onMeasure方法只是完成了尺寸大小的测量工作,布局控件还得运行onLayout方法把各个子控件摆放到指定的位置上去。

水平方向摆放方式有两种:从右到左和从左到右,这里以从左到右为例来讲解。
在这里插入图片描述
根结点摆放的方式:竖直方向居中(黄色方框高度的一半),水平方向居左。
子结点的摆放方式:竖直方向从上到下线性摆放,水平方向以 (根结点的右边+层级间隔(灰线))为左边界。

此外,还要把子控件的Margin也算进去。(本树形布局并不支持Padding,如果一个布局支持Padding,那还得把Padding的相关数值也算进去)。
在这里插入图片描述
摆放思路如上,接下来看看代码。水平和竖直方向各有两种情况,所以在onLayout方法上分别执行。

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
        switch(mTreeDirection){
            case DIRECTION_LEFT_TO_RIGHT:
                onLayoutLeftToRight(changed,l,t,r,b);
                break;

            case DIRECTION_RIGHT_TO_LEFT:
                onLayoutRightToLeft(changed,l,t,r,b);
                break;

            case DIRECTION_UP_TO_DOWN:
                onLayoutUpToDown(changed,l,t,r,b);
                break;

            case DIRECTION_DOWN_TO_UP:
                onLayoutDownToUp(changed,l,t,r,b);
                break;
        }
}

接下来看看从左到右摆放的具体代码实现。

protected void onLayoutLeftToRight(boolean changed, int l, int t, int r, int b){
        int childCount = getChildCount();

        if(childCount <= 0){
            return;
        }

        View root = getChildAt(0);
        LayoutParams rootLayoutParams = (LayoutParams) root.getLayoutParams();

        int rootLeft = rootLayoutParams.leftMargin;
        int rootTop = (mWrapHeight - root.getMeasuredHeight()) / 2 + rootLayoutParams.topMargin;

        root.layout(rootLeft,
                rootTop,
                rootLeft + root.getMeasuredWidth(),
                rootTop + root.getMeasuredHeight());

        int childLeftWithoutMargin = rootLeft + root.getMeasuredWidth() + rootLayoutParams.rightMargin + mLevelInterval;
        int childLeft;
        int childTop = 0;

        for(int i = 1;i < childCount;i++){
            View child = getChildAt(i);
            //1
            if(child.getVisibility() == View.GONE){
                continue;
            }
            LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
            childLeft = childLeftWithoutMargin + layoutParams.leftMargin;
            childTop += layoutParams.topMargin;
            child.layout(childLeft,
                    childTop,
                    childLeft + child.getMeasuredWidth(),
                    childTop + child.getMeasuredHeight());
            childTop += (child.getMeasuredHeight() + layoutParams.bottomMargin);
        }
    }

注意代码1,如果一个子控件的状态是GONE,则它的宽高是无效的(注意区别INVISIBLE),这时就不必考虑它的摆放了。(onMeasure也是一样的)

最后

本篇以从左到右方向为例讲解了子控件在布局中的摆放,从右到左及竖直方向的原理也是一样的,感兴趣的朋友可以到Github项目上看看完整的代码。

下一篇讲解结点连接线的绘制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值