前面两篇已经对UI绘制流程有了大致的分析,下面开始应用一下了,写一个瀑布流布局,废话不多说,开始撸码。
UI绘制源码分析第一弹 http://www.jianshu.com/p/fe72b50931bc
UI绘制源码分析第二弹 http://www.jianshu.com/p/735ea96dcd16
正文
先来晒一下效果图~
QQ截图20171126095837.png
分析
2121017-787fea21095b43d8.png
我们要打造这种效果首先要确定自定义ViewGroup最终的宽高该如何确定,宽度是确定的,但是高度要怎么确定呢?我们可以定义一个数组,数组的长度为列数,里面的值存储每列的高度,最终最大的高度则为最终自定义ViewGroup的高度
撸码
onMeasure方法
-
得到size和mode
int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); -
开始进行测量
measureChildren(widthMeasureSpec, heightMeasureSpec);//只有执行了这个下面才能使用childView.getMeasureWidth()方法 int count = getChildCount();//得到Item的数量 int itemWidth = (widthSize - (DEFAULT_COLUMN - 1) * SPACE) / DEFAULT_COLUMN; if (count < DEFAULT_COLUMN) {//当数量小于一行的数量 measureWidth = itemWidth * count + (count - 1) * SPACE; } else { measureWidth = widthSize; } clearTop();//;这里不要忘记重置tops数组,因为每次添加都会执行一次onMeasure方法 for (int i = 0; i < count; i++) { View childView = getChildAt(i); MyWaterfallLayout.MyLayoutParams params = (MyLayoutParams) childView.getLayoutParams();//用来存储childView的方位 int minIndex = getMinIndex(); params.l = minIndex * (itemWidth + SPACE); params.t = getMinHeight() + SPACE; params.r = params.l + itemWidth; int itemHeight = childView.getMeasuredHeight() * itemWidth / childView.getMeasuredWidth(); params.b = params.t + itemHeight; tops[minIndex] += SPACE + itemHeight; //更新Tops数组 } measureHeight = getMaxHeight();//最终得到最大的高度 } -
最终设置ViewGroup的大小
setMeasuredDimension(measureWidth, measureHeight);
onLayout方法
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
MyWaterfallLayout.MyLayoutParams params = (MyLayoutParams) childView.getLayoutParams();
childView.layout(params.l, params.t, params.r, params.b);
}
在这里定义了一个LayoutParams用来存储childView的位置,这里就避免了在onLayout方法再次进行测量
class MyLayoutParams extends LayoutParams {
int l;
int t;
int r;
int b;
public MyLayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
public MyLayoutParams(int width, int height) {
super(width, height);
}
public MyLayoutParams(LayoutParams source) {
super(source);
}
}
当你使用child.getLayoutParams的时候需要重写
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new MyLayoutParams(MyLayoutParams.WRAP_CONTENT, MyLayoutParams.WRAP_CONTENT);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MyLayoutParams(getContext(), attrs);
}










网友评论