自定義組件之規則分佈按鈕的菜單

廢話很少說,先上效果圖(下了幾個屏幕錄製軟件,效果不是很好,只能截取部分圖片了,各位有什麼好用的推薦下): java

  


  

      圖中間的圓形佈局菜單是一個繼承ViewGroup的組件,能夠動態添加外圍菜單按鈕個數,會自動圍繞中間按鈕造成一個圓圈。不過外圍的按鈕不要太多,否則會重疊,並且太多也很差看。 算法

      主要思路就是重寫ViewGroup的onMeasure()和onLayout()這兩個方法。其中onMeasure()用來計算組件所需的區域大小,能夠根據實際須要進行計算。onLayout()方法中根據需求擺放你的childView。 ide

      接下來,重點講下如何計算組件的大小。首先,組件區域確定是一塊矩形區域,本組件恰好是一個正方形。全部外圍childView圍成的圓是這個正方形區域的內接圓。假設這個正方形區域的寬和高分別爲Width和Height,中心圓的半徑爲centerR,外圍圓的半徑爲outsideR,中心圓和外圍圓之間間隔Dur,之外圍childView圍成的圓半徑爲R。那麼
工具

      Width = Height = (centerR/2 + outsideR + Dur)*2; R = centerR/2 + outsideR/2 + Dur; 佈局

正方形區域的算法就這麼簡單。可是,在onMeasure()方法中,有一個東東必定要會用,那就是MeasureSpec。關於MeasureSpec的資料已經不少了,你們能夠本身去查閱資料(這裏推薦一個http://blog.csdn.net/failure01/article/details/8577013)。它能夠理解爲用來合成或者分解組件的大小Size和模式Mode的一個工具類。另外,你們在獲取childView大小的時候,必定要先用measureChild方法測量下它們的大小。 spa

      測量組件大小講完了,再來說講childView的擺放問題。onLayout(l,t,r,b)有4個參數,分別表示該組件在屏幕上的左,上,右,下四個位置。而方法中的childView擺放要調用的layout(l,t,r,b)這4個參數,分別表示該childView在組件中的左,上,右,下四個位置。對於本組件,中心圓的位置固然是處於正中間。圓心位置爲centerX = centerY = Width/2; 那麼 .net

l = centerX - centerR, t = centerY - centerR,  r = centerX + centerR, b = centerY + centerR;
code

再來講說外圍childView的位置擺放。這是一個本組件最麻煩的環節了。由於要根據childView的個數來肯定每個childView的位置。假設兩個childView與中心圓的夾角爲θ,咱們將其中一個childView做爲基準(選取頂部的childView),其他childView依次根據偏移角度來計算位置。頂部childView的圓心位置爲(centerX - R , centerY - R)。那麼,順時針第一個childView圓心位置爲(centerX + R*sinθ,centerY - R*sinθ),第二個childView的圓心位置爲(centerX + R*sinλθ,centerY - R*sinλθ)...,有了圓心位置,那左,上,右,下的位置都是瓜熟蒂落了,哈哈。 blog

說了一大堆有點抽象,貼下代碼: 繼承

@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int widthMode = MeasureSpec.getMode(widthMeasureSpec);
		int widthSize = MeasureSpec.getSize(widthMeasureSpec);
		int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		int heightSize = MeasureSpec.getSize(heightMeasureSpec);
		
		int max_outsideWidth = 0;
		int max_outsideHeight = 0;
		
		System.out.println("widthSize: " + widthSize + ", heightSize: " + heightSize + ", widthMode: " + widthMode + ", heightMode: " + heightMode);
		
		for(int i=0; i<getChildCount(); i++){
			View child = getChildAt(i);
			Object tag = child.getTag();
			if(tag != null && centerTag.equals(tag)){
				View home = getChildAt(0);
				measureChild(home, widthMeasureSpec, heightMeasureSpec);
				centerWidth = home.getMeasuredWidth();
				centerHeight = home.getMeasuredHeight();
				//System.out.println("centerWidth: " + centerWidth + ", centerHeight: " + centerHeight);
			}else {
				measureChild(child, widthMeasureSpec, heightMeasureSpec);
				outsideWidth = child.getMeasuredWidth();
				outsideHeight = child.getMeasuredHeight();
				
				max_outsideWidth = Math.max(max_outsideWidth, outsideWidth);
				max_outsideHeight = Math.max(max_outsideHeight, outsideHeight);
				
				//System.out.println("outsideWidth"+i+": " + max_outsideWidth + ", outsideHeight"+i+": " + max_outsideWidth);
			}
		}
		
		Width = (centerWidth/2 + max_outsideWidth + dis_bt)*2 + space;
		Height = (centerHeight/2 + max_outsideHeight + dis_bt)*2 + space;
		Radius = centerWidth/2 + max_outsideWidth/2 + dis_bt;
		centerX = Width/2;
		centerY = Height/2;
		System.out.println("width: " + Width + " , height: " + Height + " , centerX: " + centerX + " , centerY: " + centerY);
		super.onMeasure(MeasureSpec.makeMeasureSpec(Width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(Height, MeasureSpec.EXACTLY));
		//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}
@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		if(changed){
			System.out.println("position is l: " + l + ", t: " + t + ", r: " + r + ", b: " + b);
			int centerW = 0,centerH = 0;
			int count = getChildCount();
			int outsideCount = count - 1;
			double ang = 2*Math.PI/outsideCount;
			int outsideIndex = 0;
			for(int i=0; i<count; i++){
				View child = getChildAt(i);
				Object tag = child.getTag();
				if(tag != null && tag.equals(centerTag)){
					centerW = child.getMeasuredWidth();
					centerH = child.getMeasuredHeight();
					System.out.println("center mw: " + centerW + ", mh: " + centerH);
					int cl = centerX - centerW/2;
					int ct = centerY - centerH/2;
					int cr = centerX + centerW/2;
					int cb = centerY + centerH/2;
					child.layout(cl, ct, cr, cb);
				}else {
					int submw = child.getMeasuredWidth();
					int submh = child.getMeasuredHeight();
					double sin = Math.sin(outsideIndex*ang);
					double cos = Math.cos(outsideIndex*ang);
					System.out.println(outsideIndex + " ang: " + ang + " , sin: " + sin + ", cos: " + cos);
					int x = (int) (centerX + Radius*sin);
					int y = (int) (centerY - Radius*cos);
					System.out.println(outsideIndex + "  x: " + x + ", y: " + y);
					outsideIndex++;
					child.layout(x-submw/2, y-submh/2, x+submw/2, y+submh/2);
				}
			}
		}
	}
最後再奉上源碼,第一次寫博文,寫的很差,條理有些亂,還請大神們指點一二。
http://download.csdn.net/detail/hatah0126/6533225
相關文章
相關標籤/搜索