標籤:
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>
Android 自訂ViewGroup(自訂版面配置容器)