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();
//?遍历每个子元素
for?(int?i?=?0;?i?<?count;?i++)?{
View?child?=?getChildAt(i);
if?(child.getVisibility()?==?GONE)
continue;
//?测量每一个child的宽和高
measureChild(child,?widthMeasureSpec,?heightMeasureSpec);
//?得到child的lp
ViewGroup.LayoutParams?lp?=?child.getLayoutParams();
//?当前子空间实际占据的宽度
int?childWidth?=?child.getMeasuredWidth()?+?childHorizontalSpace;
//?当前子空间实际占据的高度
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,类加height?然后开启新行
if?(lineWidth?+?childWidth?>?sizeWidth?-?getPaddingLeft()?-?getPaddingRight())?{
width?=?Math.max(lineWidth,?childWidth);//?取最大的
lineWidth?=?childWidth;?//?重新开启新行,开始记录
//?叠加当前高度,
height?+=?lineHeight;
//?开启记录下一行的高度
lineHeight?=?childHeight;
child.setTag(new?Location(left,?top?+?height,?childWidth
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》 浏览器打开:qq.cn.hn/FTe 开源分享
?+?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个数
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="梦回吹角连营"?/>
<TextView
style="@style/TvStyle"
android:text="八百里分麾下炙"?/>
<TextView
style="@style/TvStyle"
android:text="五十弦翻塞外声"?/>
<TextView
style="@style/TvStyle"
android:text="沙场秋点兵"?/>
<TextView
style="@style/TvStyle"
android:text="马作的卢飞快"?/>
<TextView
style="@style/TvStyle"
android:text="弓如霹雳弦惊(增加点长度)"?/>
<TextView
style="@style/TvStyle"
android:text="了却君王天下事"?/>
<TextView
style="@style/TvStyle"
android:text="赢得生前身后名"?/>
<TextView
style="@style/TvStyle"
android:text="可怜白发生!"?/>
</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,使用时记得调用recyle()方法将不用的对象返回至对象池来达到重用的目的。
attrArray.recycle();
}
写到这里自定义ViewGroup基本完成。
ViewGroup属性
联系客服