1、先创建一个控件类间接或者直接继承ViewGroup类
2、重载onMeasure方法来测量控件
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
3、重载onLayout方法来布局子空间
protected void onLayout(boolean changed, int l, int t, int r, int b)
4、重载返回ViewGroup.LayoutParams的方法
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs)
protected ViewGroup.LayoutParams generateDefaultLayoutParams()
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p)
下面实现一个圆形布局的容器
package com.example.asdlon.circleviewgroupdemo; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewGroup; public class CircleLayout extends ViewGroup { private static final String TAG = "CircleLayout"; public CircleLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public CircleLayout(Context context) { super(context); } public CircleLayout(Context context, AttributeSet attrs) { super(context, attrs); } public int Radius=50; /** * 计算所有ChildView的宽度和高度 然后根据ChildView的计算结果,设置自己的宽和高 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { /** * 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式 */ int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); Log.e(TAG, (heightMode == MeasureSpec.UNSPECIFIED) + "," + sizeHeight + "," + getLayoutParams().height); // 计算出所有的childView的宽和高 measureChildren(widthMeasureSpec, heightMeasureSpec); /** * 记录如果是wrap_content是设置的宽和高 */ int width = 0; int height = 0; int cCount = getChildCount(); int cWidth = 0; int cHeight = 0; MarginLayoutParams cParams = null; //最大的宽度的变量 int maxElementWidth = 0; //遍历所有的子对象,并调用子对象的Measure方法进行测量,取出最大的宽度的子对象 for (int i = 0; i < cCount; i++) { //测量子对象 View childView = getChildAt(i); cWidth = childView.getMeasuredWidth(); maxElementWidth = Math.max(cWidth, sizeWidth); } //两个半径的大小和最大的宽度的两倍最为面板的宽度 int panelWidth = 2 * this.Radius + 2 * maxElementWidth; //取面板的所分配的高度宽度和计算出来的宽度的最小值最为面板的实际大小 int width2 = Math.min(panelWidth, sizeWidth); int heigh2 = Math.min(panelWidth, sizeWidth); setMeasuredDimension(width2, heigh2); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int cCount = getChildCount(); int cWidth = 0; int cHeight = 0; MarginLayoutParams cParams = null; /** * 遍历所有childView根据其宽和高,以及margin进行布局 */ //当前的角度,从0开始排列 double degree = 0; //计算每个子对象所占用的角度大小 double degreeStep = (double)360 / cCount; //计算 int pWidth= getWidth(); double mX = pWidth / 2; int pHeight= getHeight(); double mY = pHeight / 2; //遍历所有的子对象进行排列 for (int i = 0; i < cCount; i++) { View childView = getChildAt(i); cWidth = childView.getMeasuredWidth(); cHeight = childView.getMeasuredHeight(); cParams = (MarginLayoutParams) childView.getLayoutParams(); //把角度转换为弧度单位 double angle = Math.PI * degree / 180.0; //根据弧度计算出圆弧上的x,y的坐标值 double x = Math.cos(angle) * this.Radius; double y = Math.sin(angle) * this.Radius; childView.setPivotX(0); childView.setPivotY(0); childView.setRotation((float)degree); childView.layout((int)(mX + x), (int)(mY + y),(int)(mX + x+cWidth), (int)(mY + y+cHeight)); Log.e(TAG, "mX"+(int)mX+"mY"+(int)mY+"x"+(int)x+"y"+(int)y+"degree"+degree+"cWidth"+cWidth+"cHeight"+cHeight); //角度递增 degree += degreeStep; } } @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { Log.e(TAG, "generateDefaultLayoutParams"); return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected ViewGroup.LayoutParams generateLayoutParams( ViewGroup.LayoutParams p) { Log.e(TAG, "generateLayoutParams p"); return new MarginLayoutParams(p); } }
<com.example.asdlon.circleviewgroupdemo.CircleLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#AA333333" > <TextView android:layout_width="150dp" android:layout_height="50dp" android:background="#E5ED05" android:text="0000000" android:textColor="#FFFFFF" android:textSize="22sp" android:textStyle="bold" /> <TextView android:layout_width="150dp" android:layout_height="50dp" android:background="#00ff00" android:text="1111111" android:textColor="#FFFFFF" android:textSize="22sp" android:textStyle="bold" /> <TextView android:layout_width="150dp" android:layout_height="50dp" android:background="#ff0000" android:text="2222222222" android:textColor="#FFFFFF" android:textSize="22sp" android:textStyle="bold" /> <TextView android:layout_width="150dp" android:layout_height="50dp" android:background="#0000ff" android:gravity="center" android:text="333333" android:textColor="#FFFFFF" android:textSize="22sp" android:textStyle="bold" /> </com.example.asdlon.circleviewgroupdemo.CircleLayout>