自定义控件系列:
秒懂OnMeasure
秒懂OnLayout
让自定义ViewGroup里的子控件支持Margin
让自定义ViewGroup支持Padding
自定义ViewGroup的一个综合实践 FlowLayout
知识点:
- 让自定义ViewGroup支持Padding,需要自定义ViewGroup在自身的onMeasure和onLayout里去处理Padding即可
因为padding很容易获得,不像是Margin那么麻烦,
另外与margin不同的是,padding是自定义ViewGroup的padding,只有四个padding,而margin是子控件的margin,每个子控件都会有四个margin,所有在处理上注意一下
应用
1. 支持padding
第一步:onMeasure里处理Padding
其实就是在AT_MOST模式下,让ViewGroup自身的宽高加上padding,变大一点
EXACTLY模式是不用处理的,因为他已经指定了宽高,按照他指定的来就行了
/**
* 计算本View在AtMost模式下的宽高
* 其他代码都是不用动的,在这里写下你特有的逻辑就可以
*
* @param widthMeasureSpec
* @param heightMeasureSpec
* @return
*/
private Point caculateAtMostSize(int widthMeasureSpec, int heightMeasureSpec) {
int width = 0;
int height = 0;
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
// 测量一下子控件的宽高
measureChild(child, widthMeasureSpec, heightMeasureSpec);
// 得到MarginLayoutParams,margin就在这里保存着
MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
// 获得子控件的宽高(需要加上对应的margin,让控件的宽高包含margin,
// 这样才能让自定义的viewgroup在计算自身在AtMost模式的尺寸时候考虑到这些margin)
int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
// 因为我们的自定义View模拟的是竖向的LinearLayout,所以:
// 控件的宽度为所有子控件里,宽度最大的那个view的宽度,
// 控件高度是所有子空间的高度之和
width = Math.max(childWidth, width);
height += childHeight;
}
width += (getPaddingLeft() + getPaddingRight());
height += (getPaddingTop() + getPaddingBottom());
return new Point(width, height);
}
第二步:onLayout里处理Padding
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int top = getPaddingTop();
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
// 得到MarginLayoutParams,margin就在这里保存着
MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
// 获得子控件的宽高(需要加上对应的margin,让控件的宽高包含margin)
int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
// 布局,就是设置好这个子控件的左上右下
// 在布局的时候,考虑控件的margin,把子view摆放好
// (这是一个竖向的LinearLayout,想想如何布置子控件)
child.layout(lp.leftMargin+getPaddingLeft(),
top + lp.topMargin,
childWidth - lp.rightMargin+getPaddingLeft(),
top + childHeight - lp.bottomMargin);
top += childHeight;
}
}
github源码之MyLinearLayoutWithMarginAndPadding
至此
- 自定义View(含Viewgroup)onMeasure里支持AT_MOST的模板代码
- 自定义Viewgroup的onLayout里支持Margin的模板代码
都有了,真的是一样的套路,照抄即可 - 另外处理Margin和Padding的一些小逻辑,仔细想想也很容易写出来,大思路有了,小逻辑调试一下就出来了
参考:
《Android自定义开发入门与实践》感谢大神的著作