700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > android 自定义控件viewgroup Android 之 自定义控件 之 ViewGroup

android 自定义控件viewgroup Android 之 自定义控件 之 ViewGroup

时间:2024-04-12 03:17:03

相关推荐

android 自定义控件viewgroup Android 之 自定义控件  之 ViewGroup

介绍

ViewGroup相当于一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性,都是为用于告诉容器的),我们的宽度(layout_width)、高度(layout_height)、对齐方式(layout_gravity)等;当然还有margin等;于是乎,ViewGroup的职能为:给childView计算出建议的宽和高和测量模式 ;决定childView的位置;为什么只是建议的宽和高,而不是直接确定呢,别忘了childView宽和高可以设置为wrap_content,这样只有childView才能计算出自己的宽和高。

方法介绍

onLayout:用于确定子view在布局中的位置

onMeasure:用于计算和谁在ViewGroup的宽高

generateLayoutParams:生成的LayoutParams 如果我们需要支持margin,需要使用系统的MarginLayoutParams。

View的3种测量模式

上面提到了ViewGroup会为childView指定测量模式,下面简单介绍下三种测量模式:

EXACTLY:表示设置了精确的值,一般当childView设置其宽、高为精确值、match_parent时,ViewGroup会将其设置为EXACTLY;

AT_MOST:表示子布局被限制在一个最大值内,一般当childView设置其宽、高为wrap_content时,ViewGroup会将其设置为AT_MOST;

UNSPECIFIED:表示子布局想要多大就多大,一般出现在AadapterView的item的heightMode中、ScrollView的childView的heightMode中;此种模式比较少见。

如何定义

1.创建自己的ViewGroup

public class MyViewGroup extends ViewGroup {

private Context context;

public MyViewGroup(Context context) {

super(context);

this.context = context;

}

//如果通过XML配置 需要重写带属性的方法

public MyViewGroup(Context context, AttributeSet attrs) {

super(context, attrs);

this.context = context;

}

}

2.重写onMeasure方法,测量指定容器大小

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

/**

* 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式

*/

int widthMode = MeasureSpec.getMode(widthMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);

int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

int height = 0;

// 遍历每个子元素 测量子控件的宽高

for (int i = 0; i < getChildCount(); i++)

{

View child = getChildAt(i);

// 测量每一个child的宽和高

measureChild(child, widthMeasureSpec, heightMeasureSpec);

// 得到child的lp

MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

// 当前子空间实际占据的宽度

int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;

// 当前子空间实际占据的高度

int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;

//总高度

height+=childHeight;

}

//确认模式

if(heightMode==MeasureSpec.AT_MOST){

setMeasuredDimension(sizeWidth,cHeight);

}else{

setMeasuredDimension(sizeWidth,sizeHeight);

}

}

因为需要获Margin所以需要重写该方法生成我们的LayoutParams,否则会报出 类型转换异常

@Override

public LayoutParams generateLayoutParams(AttributeSet attrs) {

return new MarginLayoutParams(getContext(),attrs);

}

3.onLayout对所有的childView进行布局

/**

* 定位子控件位置 其参数 用于自身对于 外控件的 坐标

* @param changed

* @param l

* @param t

* @param r

* @param b

*/

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

int paddingBottom = getPaddingBottom();

int paddingLeft = getPaddingLeft();

int paddingRight = getPaddingRight();

int paddingTop = getPaddingTop();

int childCount = getChildCount();

int cWidth = 0;

cHeight = 0;

for (int i=0;i

View childView = getChildAt(i);

// int width = childView.getWidth(); 与 getMeasuredWidth 区别在于

// 都是获取控件宽度 实现方式不一样,其次 getWidth在onMeasure 中无法获取到

int measuredWidth = childView.getMeasuredWidth();

int measuredHeight = childView.getMeasuredHeight();

MarginLayoutParams layoutParams = (MarginLayoutParams) childView.getLayoutParams();

//设置子View所处的位置

//childView.layout(int l, int t, int r, int b) ; //l:左边 t:上边 r:右边 b:下边 的位置坐标

childView.layout(0,cHeight+layoutParams.topMargin,measuredWidth-paddingRight,cHeight+measuredHeight+layoutParams.topMargin);

cHeight +=layoutParams.topMargin; //追加 magin

cHeight +=measuredHeight; //追加 之前的高度

}

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。