上一篇以水平方向为例讲解了树形布局的宽高测量,本篇讲解子控件的摆放。水平树的摆放原理和竖直方向的摆放原理是一样的,这里就继续顺着水平树的思路进行。
重写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项目上看看完整的代码。
下一篇讲解结点连接线的绘制