自定义ViewGroup,你真正懂了吗?
2016-09-19 本文已影响440人
码无止境
背景
自定义View简单,因为它只需管好自己即可,而自定义ViewGroup不仅仅要管好自己,还要管好子View。接触过ViewGroup的童鞋应该都清楚,ViewGroup是作为一个View的容器,它装着子View并将子View放到指定位置上去。
目的
让大家举一反三地去自定义定制化的GroupView
思路
自定义GroupView思路
- 首先需要知道子View大小,然后才能确定自定义的GroupView如何设置才能容纳它们。
- 根据子View的大小和ViewGroup需要实现的效果,确定最终ViewGroup的大小。
- ViewGroup和子View的大小确定后,接着就是如何去摆放子View,你可以按照自己特定的规则去摆放。
- 然后将子View对号入座放入已知的分割单元。
实践
接下来我做一个示例将子View按从左到右顺序一个挨着一个摆放,即模仿实现LinearLayout的横向布局。
首先重写onMeasure,测量子View大小以及设定ViewGroup最终大小,代码如下:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 对所有子view进行测量,触发所有子view的onMeasure函数
measureChildren(widthMeasureSpec, heightMeasureSpec);
// 宽度模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
// 测量宽度
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
// 高度模式
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
// 测量高度
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// 子view数目
int childCount = getChildCount();
if (childCount == 0){
// 如果当前ViewGroup没有子View,就没有存在的意义,无需占空间
setMeasuredDimension(0, 0);
}else {
// 如果宽高都是包裹内容
if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){
// 宽度为所有子view宽度相加,高度取子view最大高度
int width = getTotalWidth();
int height = getMaxHeight();
setMeasuredDimension(width, height);
}else if (widthMode == MeasureSpec.AT_MOST){
// 宽度为所有子View宽度相加,高度为测量高度
setMeasuredDimension(getTotalWidth(), heightSize);
}else if (heightMode == MeasureSpec.AT_MOST){
// 宽度为测量宽度,高度为子view最大高度
setMeasuredDimension(widthSize, getMaxHeight());
}
}
}
/**
* 获取子view最大高度
* @author leibing
* @createTime 2016/09/19
* @lastModify 2016/09/19
* @param
* @return
*/
private int getMaxHeight() {
// 最大高度
int maxHeight = 0;
// 子view数目
int childCount = getChildCount();
// 遍历子view拿取最大高度
for (int i=0;i<childCount;i++){
View childView = getChildAt(i);
if (childView.getMeasuredHeight() > maxHeight)
maxHeight = childView.getMeasuredHeight();
}
return maxHeight;
}
/**
* 所有子view宽度相加
* @author leibing
* @createTime 2016/09/19
* @lastModify 2016/09/19
* @param
* @return
*/
private int getTotalWidth() {
// 所有子view宽度之和
int totalWidth = 0;
// 子View数目
int childCount = getChildCount();
// 遍历所有子view拿取所有子view宽度之和
for (int i=0;i<childCount;i++){
View childView = getChildAt(i);
totalWidth += childView.getMeasuredWidth();
}
return totalWidth;
}
接下来将子View摆放到合适的位置上去,代码如下:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 子view数目
int childCount = getChildCount();
// 记录当前宽度位置
int currentWidth = l;
// 逐个摆放子view
for (int i = 0;i<childCount;i++){
View childView = getChildAt(i);
int height = childView.getMeasuredHeight();
int width = childView.getMeasuredWidth();
// 摆放子view,参数分别是子view矩形区域的左、上,右,下。
childView.layout(currentWidth, t, currentWidth + width, t + height);
currentWidth += width;
}
}
运行效果图如下所示:

童鞋们,看完后,自定义ViewGroup是不是很简单了?
demo地址:[CustomView Demo]
作者
- qq:872721111
- github:leibing@github
- email:leibing1989@126.com