attrArray.recycle();
}
//此視圖是否自行繪制
setWillNotDraw(false);
}
/**
*?負責設置子控件的測量模式和大小?根據所有子控件設置自己的寬和高
*/
@Override
protected?void?onMeasure(int?widthMeasureSpec,?int?heightMeasureSpec)?{
super.onMeasure(widthMeasureSpec,?heightMeasureSpec);
MLog.e(getClass().getName(),"onMeasure");
//?獲得它的父容器為它設置的測量模式和大小
int?sizeWidth?=?MeasureSpec.getSize(widthMeasureSpec);
int?sizeHeight?=?MeasureSpec.getSize(heightMeasureSpec);
int?modeWidth?=?MeasureSpec.getMode(widthMeasureSpec);
int?modeHeight?=?MeasureSpec.getMode(heightMeasureSpec);
//?如果是warp_content情況下,記錄寬和高
int?width?=?0;
int?height?=?0;
//記錄每一行的寬度,width不斷取最大寬度
int?lineWidth?=?0;
//每一行的高度,累加至height
int?lineHeight?=?0;
int?count?=?getChildCount();
int?left?=?getPaddingLeft();
int?top?=?getPaddingTop();
//?遍歷每個(gè)子元素
for?(int?i?=?0;?i?<?count;?i++)?{
View?child?=?getChildAt(i);
if?(child.getVisibility()?==?GONE)
continue;
//?測量每一個(gè)child的寬和高
measureChild(child,?widthMeasureSpec,?heightMeasureSpec);
//?得到child的lp
ViewGroup.LayoutParams?lp?=?child.getLayoutParams();
//?當前子空間實(shí)際占據的寬度
int?childWidth?=?child.getMeasuredWidth()?+?childHorizontalSpace;
//?當前子空間實(shí)際占據的高度
int?childHeight?=?child.getMeasuredHeight()?+?childVerticalSpace;
if?(lp?!=?null?&&?lp?instanceof?MarginLayoutParams)?{
MarginLayoutParams?params?=?(MarginLayoutParams)?lp;
childWidth?+=?params.leftMargin?+?params.rightMargin;
childHeight?+=?params.topMargin?+?params.bottomMargin;
}
//如果加入當前child,則超出最大寬度,則的到目前最大寬度給width,類(lèi)加height?然后開(kāi)啟新行
if?(lineWidth?+?childWidth?>?sizeWidth?-?getPaddingLeft()?-?getPaddingRight())?{
width?=?Math.max(lineWidth,?childWidth);//?取最大的
lineWidth?=?childWidth;?//?重新開(kāi)啟新行,開(kāi)始記錄
//?疊加當前高度,
height?+=?lineHeight;
//?開(kāi)啟記錄下一行的高度
lineHeight?=?childHeight;
child.setTag(new?Location(left,?top?+?height,?childWidth
《Android學(xué)習筆記總結+最新移動(dòng)架構視頻+大廠(chǎng)安卓面試真題+項目實(shí)戰源碼講義》 瀏覽器打開(kāi):qq.cn.hn/FTe 開(kāi)源分享
?+?left?-?childHorizontalSpace,?height?+?child.getMeasuredHeight()?+?top));
}?else?{
//?否則累加值lineWidth,lineHeight取最大高度
child.setTag(new?Location(lineWidth?+?left,?top?+?height,?lineWidth?+?childWidth?-?childHorizontalSpace?+?left,?height?+?child.getMeasuredHeight()?+?top));
lineWidth?+=?childWidth;
lineHeight?=?Math.max(lineHeight,?childHeight);
}
}
width?=?Math.max(width,?lineWidth)?+?getPaddingLeft()?+?getPaddingRight();
height?+=?lineHeight;
sizeHeight?+=?getPaddingTop()?+?getPaddingBottom();
height?+=?getPaddingTop()?+?getPaddingBottom();
setMeasuredDimension((modeWidth??MeasureSpec.EXACTLY)???sizeWidth?:?width,?(modeHeight??MeasureSpec.EXACTLY)???sizeHeight?:?height);
}
/**
*?記錄子控件的坐標
*/
public?class?Location?{
public?Location(int?left,?int?top,?int?right,?int?bottom)?{
this.left?=?left;
this.top?=?top;
this.right?=?right;
this.bottom?=?bottom;
}
public?int?left;
public?int?top;
public?int?right;
public?int?bottom;
}
//計算當前View以及子View的位置
@Override
protected?void?onLayout(boolean?changed,?int?l,?int?t,?int?r,?int?b)?{
MLog.e(getClass().getName(),"onLayout");
//獲取子View個(gè)數
int?count?=?getChildCount();
for?(int?i?=?0;?i?<?count;?i++)?{
//獲取子View
View?child?=?getChildAt(i);
//判斷是否顯示
if?(child.getVisibility()?==?GONE)
continue;
//獲取子View的坐標
Location?location?=?(Location)?child.getTag();
//設置子View位置
child.layout(location.left,?location.top,?location.right,?location.bottom);
}
}
@Override
protected?void?onSizeChanged(int?w,?int?h,?int?oldw,?int?oldh)?{
super.onSizeChanged(w,?h,?oldw,?oldh);
MLog.e(getClass().getName(),"onSizeChanged");
}
@Override
protected?void?onDraw(Canvas?canvas)?{
super.onDraw(canvas);
MLog.e(getClass().getName(),"onDraw");
}
}
<com.scc.demo.view.CustomLayout?xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dimen_20"
custom:horizontalSpace="10dp"
custom:verticalSpace="20dp">
<TextView
style="@style/TvStyle"
android:text="破陣子·為陳同甫賦壯詞以寄"?/>
<TextView
style="@style/TvStyle"
android:text="宋·辛棄疾"?/>
<TextView
style="@style/TvStyle"
android:text="醉里挑燈看劍"?/>
<TextView
style="@style/TvStyle"
android:text="夢(mèng)回吹角連營(yíng)"?/>
<TextView
style="@style/TvStyle"
android:text="八百里分麾下炙"?/>
<TextView
style="@style/TvStyle"
android:text="五十弦翻塞外聲"?/>
<TextView
style="@style/TvStyle"
android:text="沙場(chǎng)秋點(diǎn)兵"?/>
<TextView
style="@style/TvStyle"
android:text="馬作的盧飛快"?/>
<TextView
style="@style/TvStyle"
android:text="弓如霹靂弦驚(增加點(diǎn)長(cháng)度)"?/>
<TextView
style="@style/TvStyle"
android:text="了卻君王天下事"?/>
<TextView
style="@style/TvStyle"
android:text="贏(yíng)得生前身后名"?/>
<TextView
style="@style/TvStyle"
android:text="可憐白發(fā)生!"?/>
</com.scc.demo.view.CustomLayout>
在app/src/main/res/values/attrs.xml中添加屬性
<declare-styleable?name="CustomLayout">
<attr?name="verticalSpace"?format="dimension"?/>
<attr?name="horizontalSpace"?format="dimension"?/>
在xml中使用
一定要添加:xmlns:test=”http://schemas.android.com/apk/res-auto”添加之后才能在xml中自定義屬性,如下代碼:
<com.scc.demo.view.CustomLayout?xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dimen_20"
custom:horizontalSpace="10dp"
custom:verticalSpace="20dp">
</com.scc.demo.view.CustomLayout>
在代碼中使用
TypedArray?attrArray?=?context.obtainStyledAttributes(attrs,?R.styleable.CustomLayout);
if?(attrArray?!=?null)?{
//參數1:獲取xml中設置的參數;參數2:獲取失敗2使用參數作為默認值
childHorizontalSpace?=?attrArray.getDimensionPixelSize(R.styleable.CustomLayout_horizontalSpace,?12);
childVerticalSpace?=?attrArray.getDimensionPixelSize(R.styleable.CustomLayout_verticalSpace,?12);
MLog.e(getClass().getName(),"HorizontalSpace:"+childHorizontalSpace+"|VerticalSpace:"+childVerticalSpace);
//TypedArray對象池的大小默認為5,使用時(shí)記得調用recyle()方法將不用的對象返回至對象池來(lái)達到重用的目的。
attrArray.recycle();
}
寫(xiě)到這里自定義ViewGroup基本完成。
ViewGroup屬性
聯(lián)系客服