前言
例子是用來理解自定義 ViewGroup 流程虐急,不建議直接使用勇哗,如需使用可根據(jù)需求進行修改润樱。
效果圖
實現(xiàn)思路
- 繼承自 ViewGroup
- 實現(xiàn) onMeasure 方法,通過子 View 的寬高來確定自己的寬高
- 實現(xiàn) onLayout 方法懊缺,擺放子 View 的位置
TagLayout
public class TagLayout extends ViewGroup {
public TagLayout(Context context) {
this(context, null);
}
public TagLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TagLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
onMeasure
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mChildViews.clear();
//獲取子View的個數(shù)
int childCount = getChildCount();
//父View的寬度
int width = MeasureSpec.getSize(widthMeasureSpec);
//需要計算的高度
int height = getPaddingTop() + getPaddingBottom();
//單行的寬度
int lineWidth = getPaddingLeft();
//存放一行的View
List<View> childViews = new ArrayList<>();
mChildViews.add(childViews);
//處理單行不換行情況
int maxHeight = 0;
//循環(huán)測量子View
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
//測量子View的寬高
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
//獲取子View的 margin
MarginLayoutParams params = (MarginLayoutParams) childView.getLayoutParams();
//子View占據(jù)的寬度
int childWidth = childView.getMeasuredWidth() + params.leftMargin + params.rightMargin;
//子View占據(jù)的高度
int childHeight = childView.getMeasuredHeight() + params.topMargin + params.bottomMargin;
//根據(jù)子View的寬度來處理換行
if (lineWidth + childWidth > width) {
//換行
height += maxHeight;
lineWidth = childWidth;
childViews = new ArrayList<>();
mChildViews.add(childViews);
} else {
//累加寬度
lineWidth += childWidth;
maxHeight = Math.max(childHeight, maxHeight);
}
childViews.add(childView);
}
height += maxHeight;
//設置寬高
setMeasuredDimension(width, height);
}
onMeasure 方法需要記錄換行的信息巨税,每一行有多少個子 View蟋定,最終確定自己的高度
onLayout
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left;
int top = getPaddingTop();
int right;
int bottom;
int maxHeight = 0;
for (List<View> childViews : mChildViews) {
left = getPaddingLeft();
for (View childView : childViews) {
//獲取子View的 margin
MarginLayoutParams params = (MarginLayoutParams) childView.getLayoutParams();
left += params.leftMargin;
int childTop = top + params.topMargin;
right = left + childView.getMeasuredWidth();
bottom = childTop + childView.getMeasuredHeight();
Log.d("TAG", "left -> " + left + " top ->" + top + " right -> " + right + " bottom ->" + bottom);
//擺放
childView.layout(left, childTop, right, bottom);
left += childView.getMeasuredWidth() + params.rightMargin;
int childHeight = childView.getMeasuredHeight() + params.topMargin + params.bottomMargin;
maxHeight = Math.max(childHeight, maxHeight);
}
top += maxHeight;
}
}
便利每行子 View 集合,設置子 View 擺放的位置草添,如果一行不止一個子 View 需要將 left 累加。一行行便利扼仲,最終擺放出正確的位置