今天偶然看到一個圓盤形的菜單,還可以轉動,感覺挺有意思,然後想了想,做了個簡單的效果。 思路是這樣的,定一個原點和一個半徑,圓的四周均勻分佈每個菜單。爲了方便計算,菜單的座標用度數表示,然後轉化爲極座標計算。 定某個點爲起始點,根據總菜單數確定每個點增加的度數,然後依次確定每個點的度數,也就確定了座標。
package chroya.demo.roundspin; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.Log; import android.view.MotionEvent; import android.view.View; /** * 圓盤式的view * @author chroya * */ public class RoundSpinView extends View { private Paint mPaint = new Paint(); //stone列表 private BigStone[] mStones; //數目 private static final int STONE_COUNT = 6; //圓心座標 private int mPointX=0, mPointY=0; //半徑 private int mRadius = 0; //每兩個點間隔的角度 private int mDegreeDelta; public RoundSpinView(Context context, int px, int py, int radius) { super(context); mPaint.setColor(Color.RED); mPaint.setStrokeWidth(2); setBackgroundResource(R.drawable.menubkground); mPointX = px; mPointY = py; mRadius = radius; setupStones(); computeCoordinates(); } /** * 初始化每個點 */ private void setupStones() { mStones = new BigStone[STONE_COUNT]; BigStone stone; int angle = 0; mDegreeDelta = 360/STONE_COUNT; for(int index=0; index<STONE_COUNT; index++) { stone = new BigStone(); stone.angle = angle; stone.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.menu1+index); angle += mDegreeDelta; mStones[index] = stone; } } /** * 重新計算每個點的角度 */ private void resetStonesAngle(float x, float y) { int angle = computeCurrentAngle(x, y); Log.d("RoundSpinView", "angle:"+angle); for(int index=0; index<STONE_COUNT; index++) { mStones[index].angle = angle; angle += mDegreeDelta; } } /** * 計算每個點的座標 */ private void computeCoordinates() { BigStone stone; for(int index=0; index<STONE_COUNT; index++) { stone = mStones[index]; stone.x = mPointX+ (float)(mRadius * Math.cos(stone.angle*Math.PI/180)); stone.y = mPointY+ (float)(mRadius * Math.sin(stone.angle*Math.PI/180)); } } /** * 計算第一個點的角度 * @param x * @param y * @return */ private int computeCurrentAngle(float x, float y) { float distance = (float)Math.sqrt(((x-mPointX)*(x-mPointX) + (y-mPointY)*(y-mPointY))); int degree = (int)(Math.acos((x-mPointX)/distance)*180/Math.PI); if(y < mPointY) { degree = -degree; } Log.d("RoundSpinView", "x:"+x+",y:"+y+",degree:"+degree); return degree; } @Override public boolean dispatchTouchEvent(MotionEvent event) { resetStonesAngle(event.getX(), event.getY()); computeCoordinates(); invalidate(); return true; } @Override public void onDraw(Canvas canvas) { canvas.drawPoint(mPointX, mPointY, mPaint); for(int index=0; index<STONE_COUNT; index++) { if(!mStones[index].isVisible) continue; drawInCenter(canvas, mStones[index].bitmap, mStones[index].x, mStones[index].y); //不想有紅線,就注掉下面這句 // canvas.drawLine(mPointX, mPointY, mStones[index].x, mStones[index].y, mPaint); } } /** * 把中心點放到中心處 * @param canvas * @param bitmap * @param left * @param top */ void drawInCenter(Canvas canvas, Bitmap bitmap, float left, float top) { canvas.drawPoint(left, top, mPaint); canvas.drawBitmap(bitmap, left-bitmap.getWidth()/2, top-bitmap.getHeight()/2, null); } class BigStone { //圖片 Bitmap bitmap; //角度 int angle; //x座標 float x; //y座標 float y; //是否可見 boolean isVisible = true; } }
代碼裏註釋也很清楚。STONE_COUNT表示菜單的數目,可以設置爲1到7,更大的數字需要圖片支持,我只放了7張圖片。
如果觸摸的點不在圓周上,會自動計算出點到圓心的直線跟圓的交點,然後映射上去。
5個菜單的效果,畫了線的:
6個菜單的效果:
Ok,代碼也貢獻出來。