您的位置:首页 > 其它

实现自定义ViewGroup的一个精简例子

2014-05-09 18:45 281 查看
此自定义VIewGroup只做演示用,目前的代码限制其只能包含一个子View,子View可以设置间距、layout_gravity属性,以下分别为我测试用的布局文件和自定义的ViewGroup类的源码:

测试activity的布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

<com.mytest.OnlyOneChildViewViewGroup

android:layout_width="match_parent"

android:layout_height="400dp"

android:layout_marginLeft="30dp"

android:layout_marginTop="100dp"

android:background="#ff0000"

android:paddingLeft="20dp" >

<TextView

android:id="@+id/textViewTest"

android:layout_width="200dp"

android:layout_height="wrap_content"

android:layout_margin="10dp"

android:layout_gravity="right|bottom"

android:background="#00ff00"

android:text="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789......"

android:textSize="30sp" />

</com.carter.launcher.OnlyOneChildViewViewGroup>

</LinearLayout>

自定义ViewGroup类的源码:

public class OnlyOneChildViewViewGroup extends ViewGroup {

public OnlyOneChildViewViewGroup(Context context, AttributeSet attrs) {

super(context, attrs);

}

//设置ViewGroup及其子View的合适大小

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

if (getChildCount() > 0) {

final View child = getChildAt(0);

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

int leftPaddingMargin = getPaddingLeft() + lp.leftMargin;

int rightPaddingMargin = getPaddingRight() + lp.rightMargin;

int horizontalSpace = leftPaddingMargin + rightPaddingMargin;

int topPaddingMargin = getPaddingTop() + lp.topMargin;

int bottomPaddingMargin = getPaddingBottom() + lp.bottomMargin;

int verticalSpace = topPaddingMargin + bottomPaddingMargin;

//根据左右边距、左右间距、ViewGroup的宽度参数、子View的宽度参数得到子View在ViewGroup中实际显示宽度

int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, horizontalSpace, lp.width);

childWidthMeasureSpec = Math.min(childWidthMeasureSpec, widthMeasureSpec - horizontalSpace);

//根据上下边距、上下间距、ViewGroup的高度参数、子View的高度参数得到子View在ViewGroup中实际显示高度

int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, verticalSpace, lp.height);

childHeightMeasureSpec = Math.min(childHeightMeasureSpec, heightMeasureSpec - verticalSpace);

//设置子View在ViewGroup中的显示大小

child.measure(childWidthMeasureSpec, childHeightMeasureSpec);

if (View.GONE != child.getVisibility()) {

//根据ViewGroup布局参数中的宽高及上面子View计算出的大小参数来设置ViewGroup的显示大小

setMeasuredDimension(

Math.max(child.getMeasuredWidth() + horizontalSpace, widthMeasureSpec),

Math.max(child.getMeasuredHeight() + verticalSpace, heightMeasureSpec));

} else {

//子View设置为gone,所以设置ViewGroup的大小为其布局参数确定的大小

setMeasuredDimension(Math.max(horizontalSpace, widthMeasureSpec),

Math.max(verticalSpace, heightMeasureSpec));

}

} else {

//不包含子View时,设置ViewGroup的大小为其布局参数确定的大小

setMeasuredDimension(Math.max(getPaddingLeft() + getPaddingRight(), widthMeasureSpec),

Math.max(getPaddingTop() + getPaddingBottom(), heightMeasureSpec));

}

}

//根据ViewGroup和子View的布局参数,将子View布局在ViewGroup中的合适区域内

@Override

protected void onLayout(boolean arg0, int left, int top, int right, int bottom) {

if (getChildCount() > 0) {

final View child = getChildAt(0);

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

int leftPaddingMargin = getPaddingLeft() + lp.leftMargin;

int topPaddingMargin = getPaddingTop() + lp.topMargin;

int childLeft;

int childTop;

final int parentLeft = getPaddingLeft();

final int parentRight = right - left - getPaddingRight();

final int parentTop = getPaddingTop();

final int parentBottom = bottom - top - getPaddingBottom();

//获取子View在布局文件中定义的layout_gravity属性

final int horizontalGravity = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;

final int verticalGravity = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;

//解析layout_gravity属性中水平方向上的值

switch (horizontalGravity) {

case Gravity.LEFT:

childLeft = leftPaddingMargin;

break;

case Gravity.CENTER_HORIZONTAL:

childLeft = parentLeft + (parentRight - parentLeft - child.getMeasuredWidth()) / 2 +

lp.leftMargin - lp.rightMargin;

break;

case Gravity.RIGHT:

childLeft = parentRight - child.getMeasuredWidth() - lp.rightMargin;

break;

default:

childLeft = leftPaddingMargin;

}

//解析layout_gravity属性中垂直方向上的值

switch (verticalGravity) {

case Gravity.TOP:

childTop = topPaddingMargin;

break;

case Gravity.CENTER_VERTICAL:

childTop = parentTop + (parentBottom - parentTop - child.getMeasuredHeight()) / 2 +

lp.topMargin - lp.bottomMargin;

break;

case Gravity.BOTTOM:

childTop = parentBottom - child.getMeasuredHeight() - lp.bottomMargin;

break;

default:

childTop = topPaddingMargin;

}

//根据layout_gravity属性及间接、边距,将子View显示在ViewGroup中合适的位置区域

child.layout(childLeft, childTop, childLeft+child.getMeasuredWidth(), childTop+child.getMeasuredHeight());

}

}

//应用下面自定义的LayoutParams,而不是ViewGroup.LayoutParams

@Override

public android.view.ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {

return new LayoutParams(getContext(), attrs);

}

//应用下面自定义的LayoutParams,而不是ViewGroup.LayoutParams

@Override

protected android.view.ViewGroup.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams p) {

return new LayoutParams(p);

}

//由于要在子View中设置间距和layout_gravity属性,所以这里需要覆写ViewGroup中的LayoutParams类

public static class LayoutParams extends MarginLayoutParams {

public int gravity = -1;

public LayoutParams(Context c, AttributeSet attrs) {

super(c, attrs);

String attrName = null;

for (int i = 0; i < attrs.getAttributeCount(); i++) {

attrName = attrs.getAttributeName(i);

//这里是为了取出子View中定义的layout_gravity属性值

if ("layout_gravity".equals(attrName)) {

gravity = Integer.parseInt(new BigInteger(

//得到的返回值是0x1等形式的十六进制字符串,以下方式将此类型字符串转换为十进制整数值

attrs.getAttributeValue(i).replaceFirst("0[x X]", ""), 16).toString());

break;

}

}

}

public LayoutParams(int width, int height) {

this(width, height, -1);

}

public LayoutParams(int width, int height, int gravity) {

super(width, height);

this.gravity = gravity;

}

public LayoutParams(android.view.ViewGroup.LayoutParams source) {

super(source);

}

public LayoutParams(MarginLayoutParams source) {

super(source);

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: