自定義控件系列:
秒懂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自定義開發入門與實踐》感謝大神的著作