今天偶然看到一個圓盤形的菜單,還可以轉動,感覺挺有意思,然後想了想,做了個簡單的效果。
思路是這樣的,定一個原點和一個半徑,圓的四周均勻分布每個菜單。為了方便計算,菜單的座標用度數表示,然後轉化為極座標計算。
定某個點為起始點,根據總菜單數確定每個點增加的度數,然後依次確定每個點的度數,也就確定了座標。
Java代碼
- 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;
- }
- }
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;}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {resetStonesAngle(event.getX(), event.getY());computeCoordinates();invalidate();return true;}@Overridepublic 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,代碼也貢獻出來。
zhuanzi:http://chroya.iteye.com/blog/830682