基础知识
自定义View需要实现2个方法 onMeasure和onLayout。
通过onMeasure 自身的宽高,如果是ViewGroup,还需要对子View的宽高进行测量。
通过onLayout对所有子View进行定位。
九宫格的要求:
只有一张图片,则占据全部空间。
四张图片以内,2X2的格式。
其他则以3X3的格式进行。
通过Adapter来提供每个子View显示的内容,可以是TextView,可以是ImageView.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthValue = MeasureSpec.getSize(widthMeasureSpec);
int heightValue = MeasureSpec.getSize(heightMeasureSpec);
//获得内容展示的宽度
int widthRealValue = widthValue - getPaddingLeft() - getPaddingRight();
int heightRealValue = heightValue - getPaddingTop() - getPaddingBottom();
//获得子View的数目
int childCount = getChildCount();
int width = widthRealValue > heightRealValue ? heightRealValue : widthRealValue;
if (childCount == 1) {
lineNum = 0;
} else if (childCount < 5) {
lineNum = 1;
} else {
lineNum = 2;
}
for (int i = 0; i < childCount; i++) {
//如果只有一个子View 则父容器的高宽就是子容器的高宽
// count line n
// 1 0 1
// 2 1 2
// 3 1 2
// 4 1 2
// 5 2 3
// 6 2 3
// 7 2 3
// ... ...
int childWidth = (width - lineNum * mLineWidth) / (lineNum + 1);
getChildAt(i).measure(MeasureSpec.makeMeasureSpec(childWidth,MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(childWidth,MeasureSpec.EXACTLY));
}
setMeasuredDimension(widthValue, heightValue);
}
如上是 onMeasure()方法。其中,默认九宫格是不可以设置warp_content的,因为子View的大小是要根据父ViewGroup来确定的,所以onMeasure()中只关心了MeasureSpec.getSize(),而没有关注mode。通过确定宽度和高度的较小值,来确定实际的宽高。每个子View的宽度就是父View宽度减去左右padding,再减去可能存在的分割线的宽度,最后根据每行几个子View,由除法获得。测量每个子View。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
int left = l + getPaddingLeft();
int top = t + getPaddingTop();
View childView = getChildAt(i);
int viewWidth = childView.getMeasuredWidth();
switch (lineNum) {
case 0:
break;
case 1: {
if (i % 2 == 1) {
left = left + viewWidth + mLineWidth;
}
if (i > 1) {
top = top + viewWidth + mLineWidth;
}
}
break;
case 2:
int n = i % 3;
left = left + (viewWidth + mLineWidth) * n;
if (i > 5) {
top = top + 2 * (viewWidth + mLineWidth);
} else if (i > 2) {
top = top + viewWidth + mLineWidth;
}
break;
}
childView.layout(left, top, left + viewWidth, top + viewWidth);
}
我对onLayout()方法的理解是,获得每个子View的坐标(left,top),然后childView.layout()