Android简单的圆盘形菜单


今天偶然看到一个圆盘形的菜单,还可以转动,感觉挺有意思,然后想了想,做了个简单的效果。

思路是这样的,定一个原点和一个半径,圆的四周均匀分布每个菜单。为了方便计算,菜单的坐标用度数表示,然后转化为极坐标计算。

定某个点为起始点,根据总菜单数确定每个点增加的度数,然后依次确定每个点的度数,也就确定了坐标。

  1. package chroya.demo.roundspin;   
  2.   
  3. import Android.content.Context;   
  4. import android.graphics.Bitmap;   
  5. import android.graphics.BitmapFactory;   
  6. import android.graphics.Canvas;   
  7. import android.graphics.Color;   
  8. import android.graphics.Paint;   
  9. import android.util.Log;   
  10. import android.view.MotionEvent;   
  11. import android.view.View;   
  12.   
  13. /**  
  14.  * 圆盘式的view  
  15.  * @author chroya  
  16.  *  
  17.  */  
  18. public class RoundSpinView extends View {   
  19.     private Paint mPaint = new Paint();   
  20.        
  21.     //stone列表   
  22.     private BigStone[] mStones;   
  23.     //数目   
  24.     private static final int STONE_COUNT = 6;   
  25.        
  26.     //圆心坐标   
  27.     private int mPointX=0, mPointY=0;   
  28.     //半径   
  29.     private int mRadius = 0;   
  30.     //每两个点间隔的角度   
  31.     private int mDegreeDelta;   
  32.   
  33.     public RoundSpinView(Context context, int px, int py, int radius) {   
  34.         super(context);   
  35.         mPaint.setColor(Color.RED);   
  36.         mPaint.setStrokeWidth(2);   
  37.         setBackgroundResource(R.drawable.menubkground);   
  38.            
  39.         mPointX = px;   
  40.         mPointY = py;   
  41.         mRadius = radius;   
  42.            
  43.         setupStones();   
  44.         computeCoordinates();   
  45.     }   
  46.        
  47.     /**  
  48.      * 初始化每个点  
  49.      */  
  50.     private void setupStones() {   
  51.         mStones = new BigStone[STONE_COUNT];   
  52.         BigStone stone;   
  53.         int angle = 0;   
  54.         mDegreeDelta = 360/STONE_COUNT;   
  55.            
  56.         for(int index=0; index<STONE_COUNT; index++) {   
  57.             stone = new BigStone();   
  58.             stone.angle = angle;   
  59.             stone.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.menu1+index);               
  60.             angle += mDegreeDelta;   
  61.                
  62.             mStones[index] = stone;   
  63.         }   
  64.     }   
  65.        
  66.     /**  
  67.      * 重新计算每个点的角度  
  68.      */  
  69.     private void resetStonesAngle(float x, float y) {   
  70.         int angle = computeCurrentAngle(x, y);   
  71.         Log.d("RoundSpinView""angle:"+angle);   
  72.         for(int index=0; index<STONE_COUNT; index++) {              
  73.             mStones[index].angle = angle;          
  74.             angle += mDegreeDelta;   
  75.         }   
  76.     }   
  77.        
  78.     /**  
  79.      * 计算每个点的坐标  
  80.      */  
  81.     private void computeCoordinates() {   
  82.         BigStone stone;   
  83.         for(int index=0; index<STONE_COUNT; index++) {   
  84.             stone = mStones[index];   
  85.             stone.x = mPointX+ (float)(mRadius * Math.cos(stone.angle*Math.PI/180));   
  86.             stone.y = mPointY+ (float)(mRadius * Math.sin(stone.angle*Math.PI/180));   
  87.         }   
  88.     }   
  89.        
  90.     /**  
  91.      * 计算第一个点的角度  
  92.      * @param x  
  93.      * @param y  
  94.      * @return  
  95.      */  
  96.     private int computeCurrentAngle(float x, float y) {        
  97.         float distance = (float)Math.sqrt(((x-mPointX)*(x-mPointX) + (y-mPointY)*(y-mPointY)));   
  98.         int degree = (int)(Math.acos((x-mPointX)/distance)*180/Math.PI);   
  99.         if(y < mPointY) {   
  100.             degree = -degree;   
  101.         }   
  102.            
  103.         Log.d("RoundSpinView""x:"+x+",y:"+y+",degree:"+degree);   
  104.         return degree;   
  105.     }   
  106.        
  107.     @Override  
  108.     public boolean dispatchTouchEvent(MotionEvent event) {   
  109.         resetStonesAngle(event.getX(), event.getY());   
  110.         computeCoordinates();   
  111.         invalidate();   
  112.         return true;   
  113.     }   
  114.        
  115.     @Override  
  116.     public void onDraw(Canvas canvas) {   
  117.         canvas.drawPoint(mPointX, mPointY, mPaint);   
  118.            
  119.         for(int index=0; index<STONE_COUNT; index++) {   
  120.             if(!mStones[index].isVisible) continue;   
  121.             drawInCenter(canvas, mStones[index].bitmap, mStones[index].x, mStones[index].y);   
  122.             //不想有红线,就注掉下面这句   
  123. //          canvas.drawLine(mPointX, mPointY, mStones[index].x, mStones[index].y, mPaint);   
  124.         }   
  125.     }   
  126.        
  127.     /**  
  128.      * 把中心点放到中心处  
  129.      * @param canvas  
  130.      * @param bitmap  
  131.      * @param left  
  132.      * @param top  
  133.      */  
  134.     void drawInCenter(Canvas canvas, Bitmap bitmap, float left, float top) {   
  135.         canvas.drawPoint(left, top, mPaint);   
  136.         canvas.drawBitmap(bitmap, left-bitmap.getWidth()/2, top-bitmap.getHeight()/2null);   
  137.     }      
  138.        
  139.     class BigStone {   
  140.            
  141.         //图片   
  142.         Bitmap bitmap;   
  143.            
  144.         //角度   
  145.         int angle;   
  146.            
  147.         //x坐标   
  148.         float x;   
  149.            
  150.         //y坐标   
  151.         float y;   
  152.            
  153.         //是否可见   
  154.         boolean isVisible = true;   
  155.     }   
  156. }  

代码里注释也很清楚。STONE_COUNT表示菜单的数目,可以设置为1到7,更大的数字需要图片支持,我只放了7张图片。

如果触摸的点不在圆周上,会自动计算出点到圆心的直线跟圆的交点,然后映射上去。

5个菜单的效果,画了线的:

Android

6个菜单的效果:

Android

Ok,代码也贡献出来。


点击这里下载代码。

相关内容