android 自定义控件--(圆盘形菜单控件)

思路原理:

定一个原点和一个半径,圆的四周均匀分布每个菜单。为了方便计算,菜单的坐标用度数表示,然后转化为极坐标计算。定某个点为起始点,根据总菜单数确定每个点增加的度数,然后依次确定每个点的度数,也就确定了坐标。

 

源代码:

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


自定义组件调用:

[html]  view plain copy
  1. public class Main extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(new RoundSpinView(getApplicationContext(), 150, 150, 100));  
  7.     }  
  8. }  


效果截图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值