<?xml version="1.0" encoding="utf-8"?> <resources> <!-- 给我们的viewgroup定义专属的自己的属性 并且指定类型 --> <declare-styleable name="custom_view_group"> <attr name="horizontal_spacing" format="dimension" /> <attr name="vertical_spacing" format="dimension" /> </declare-styleable> </resources>
<?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="horizontal_spacing">10dp</dimen> <dimen name="vertical_spacing">10dp</dimen> </resources>
package com.yufeng.androidtest; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; public class CustomViewGroup extends ViewGroup { private int mHorizontalSpacing; private int mVerticalSpacing; private CustomLayoutParams[] point; public CustomViewGroup(Context context, AttributeSet attrs) { super(context, attrs); initCustomViewGroup(context, attrs); } private void initCustomViewGroup(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.custom_view_group); // 获取默认的间距并赋值给定制的属性 mHorizontalSpacing = typedArray.getDimensionPixelSize( R.styleable.custom_view_group_horizontal_spacing, getResources() .getDimensionPixelSize(R.dimen.horizontal_spacing)); mVerticalSpacing = typedArray.getDimensionPixelSize( R.styleable.custom_view_group_vertical_spacing, getResources() .getDimensionPixelSize(R.dimen.vertical_spacing)); // 释放 typedArray.recycle(); } public CustomViewGroup(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 存放每个控件的点用自己写的CustomLayoutParams // 用于子控件的x和y轴位置以及本控件的最终大小 int width = 0; int height = 0; // 获取本控件下子控件的个数 final int count = getChildCount(); point = new CustomLayoutParams[count]; for (int i = 0; i < count; i++) { // 获取子控件 View child = getChildAt(i); // 测量子控件的长度让子控件去搞吧,反正系统写好了,如果子控件还有子控件他也会才处理的 measureChild(child, widthMeasureSpec, heightMeasureSpec); // 计算好我们给设定的子控件位置 定制自己的控件 width = getPaddingLeft() + mHorizontalSpacing * i; height = getPaddingTop() + mVerticalSpacing * i; // 保存到子控件的点到CustomLayoutParams中 CustomLayoutParams customLayoutParams = new CustomLayoutParams(); customLayoutParams.x = width; customLayoutParams.y = height; point[i] = customLayoutParams; } width += getPaddingRight() + getChildAt(count - 1).getMeasuredWidth(); height += getPaddingBottom() + getChildAt(count - 1).getMeasuredHeight(); // 必须调用计算自己的大小 setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec)); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 把他和控件都画出来 final int count = getChildCount(); for (int i = 0; i < count; i++) { // 获取子控件 View view = getChildAt(i); // 画控件,就是从那画到那 view.layout(point[i].x, point[i].y, point[i].x + view.getMeasuredWidth(), point[i].y + view.getMeasuredHeight()); } } class CustomLayoutParams { // 用作保存点 int x; int y; } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cascade="http://schemas.android.com/apk/res/com.yufeng.androidtest" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <!--xmlns:cascade 使用自定义的属性必须声明引用 只需要把后半部分改成你的包名即可 --> <com.yufeng.androidtest.CustomViewGroup android:id="@+id/customViewGroup1" android:layout_width="match_parent" android:layout_height="match_parent" cascade:horizontal_spacing="10dp" cascade:vertical_spacing="10dp" > <View android:layout_width="100dp" android:layout_height="100dp" android:background="#FF0000" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#00FF00" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#0000FF" /> </com.yufeng.androidtest.CustomViewGroup> </LinearLayout>
原文:http://blog.csdn.net/u013134391/article/details/26108983