上一篇中其实对测量讲解的比较清楚了,对布局没有说。不过对于 viewGroup而言,测量完成了,也就意味着着,知道怎么布局了。
其实知道了怎么测量和布局就可以实现很多沙雕的控件了。比如流布局。当然了,如果想提供很方便的调用方式,还需要搞一些便捷的自定义属性才行。
这里展示一下,通过测量和布局实现的沙雕布局。
通过效果图可以看出来,这就是流布局了。而且带两种效果:一种就是普通的流布局,一行一行的排列;然后第二种是竖直排列的效果,是一列一列的排列。
当然了,这两种的代码差别其实不大,主要是 在测量和布局的时候,要计算好每个 item 应该占据的尺寸和位置。
大致说一下原理。
比如这种横向排列的流布局。在测量的时候,首先肯定也是测量每个 child的宽高。然后需要判断,当前这个 child是挨着上一个的后面继续排,还是换行。然后对于布局,也是一样的,如果不换行,那么当前这个 child一定是排在上一个的后面,就要计算好当前的child的l,t,r,p(上下左右四个顶点)对应的位置距离。如果换行,也是要计算这4个值。只是计算的逻辑有区别。
核心逻辑,关于计算和判断是否需要换行的代码就是下面这几行:
if (lineWidth + itemW > ws - getPaddingLeft() - getPaddingRight()) {
// 换行 ,先记录换行之前的数据
width = Math.max(width, lineWidth); // 记录的是上一行的数据
height += lineHeight; // 记录的是上一行的数据
// 换行了
lineHeight = itemH;
lineWidth = itemW;
} else {
// 不换行
lineHeight = Math.max(lineHeight, itemH);
lineWidth += itemW;
}
if (i == count - 1) {
// 最后一个 view , 记录这一行的数据
width = Math.max(width, lineWidth); // 记录的是这一行的数据
height += lineHeight; // 记录这一行的数据
}
// width/height 是 将要设置给自己(当前自定义的这个ViewGroup)的宽度/高度
看起来代码很少,而且也容易理解。但是,我要说的是,就是这里的逻辑搞得我头大,我之前想了很久,代码写的比这里复杂多了,但是没有实现想要的效果。(就是可以继续挨着就挨着,否则换行的效果)
实在没有想到要怎么实现这个逻辑,然后查了一些资料,终于写成上面这样的代码了。(可以说上面的这几行代码并非原创。)
要特别注意当前计算出来的值,是当前行的数据,还是上一行的数据。一定要计算出当前行的。
然后要注意对
child支持padding / margin的设置支持。(也是在测量和布局的时候做的逻辑)
彩蛋来了:完整代码,star me