Android滑动菜单

来源:互联网 发布:sql查询结果生成新表 编辑:程序博客网 时间:2024/06/05 18:46

http://blog.csdn.net/wangjinyu501/article/details/8819309

先上图方便大家理解,

                                                     

                                                    

                                                    

    中间绿色部分是拖动的按钮,白色区域是它活动的范围,朝不同的方向拖动,将进入不同的Activity,这就是所谓的滑动菜单。类似于滑动解锁,而且UI部分有待于提高,如果美工跟上来的话,也是不错的选择。

   下面开始实现:

   首先,肯定是绘制两个圆形,无可置疑;圆心点重合,为了区分 ,所以设置了不同颜色;
   灰色:固定不动的摇杆背景(也意味着摇杆的活动范围);
   红色:摇杆;
   然后考虑:红色摇杆肯定跟随手指触屏的位置而移动,那么这个很easy啦,只要在触屏事件中处理,将获取的触屏XY坐标赋值与摇杆XY坐标即可;这个没问题;但是紧接着在思考一个问题:
   一般情况下,我们不可能希望摇杆一直跟随手指位置,所以需要一个摇杆的活动区域,也就如同上图中的灰色区域,在灰色区域内摇杆可以随着用户的触屏位置移动,但是一旦用户触屏位置在活动区域之外,摇杆就不应该跑出灰色区域;所以具体实现步骤如下:
1) 得到通过摇杆的坐标与触屏点的坐标得到所形成的角度Angle
2) 根据Angle,以及已知所在圆的半径,算出摇杆所在灰色圆形上做圆周运动的当前X,Y坐标;
首先第一步: 算出摇杆坐标与触屏坐标形成的角度
我们肯定已知摇杆当前坐标,并且当用户触屏时的坐标也可以在触屏按键中得到,那么获取的方法就可以写成一个方法,方法如下:

[java] view plaincopy
  1. /*** 
  2.      * 得到两点之间的弧度 
  3.      */  
  4.     public double getRad(float px1, float py1, float px2, float py2) {  
  5.           
  6.         float x = px2 - px1;// 得到两点X的距离  
  7.         float y = py1 - py2;// 得到两点Y的距离   
  8.         float xie = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));// 算出斜边长   
  9.         float cosAngle = x / xie;// 得到这个角度的余弦值(通过三角函数中的定理 :邻边/斜边=角度余弦值)   
  10.         float rad = (float) Math.acos(cosAngle);// 通过反余弦定理获取到其角度的弧度   
  11.         if (py2 < py1) {// 注意:当触屏的位置Y坐标<摇杆的Y坐标我们要取反值-0~-180  
  12.             rad = -rad;  
  13.         }  
  14.         return rad;  
  15.     }  
   在Java中 Math类中的反余弦函数返回的不是角度是弧度,这一点要格外注意;另外一点就是,因为三角函数角度范围是0~180度,所以反之应该是-0~-180度;通过此函数获取到摇杆与用户触屏位置所形成的角度之后,我们就可以通过圆周公式来得到其摇杆的XY坐标了,方法如下:

[java] view plaincopy
  1. /** 
  2.      *      圆周运动的旋转点 
  3.      * @param centerX 旋转点X        
  4.      * @param centerY  旋转点Y           
  5.      * @param rad 旋转的弧度            
  6.      */  
  7.     public void getXY(float centerX, float centerY, float R, double rad) {  
  8.         // 获取圆周运动的X坐标  
  9.         SmallRockerCircleX = (float) (R * Math.cos(rad)) + centerX;  
  10.         // 获取圆周运动的Y坐标  
  11.         SmallRockerCircleY = (float) (R * Math.sin(rad)) + centerY;  
  12.     }  
    圆周运动公式:通过三角函数定理得出:
    X坐标:所在圆的半径*角度的余弦值
    Y坐标:所在圆形半径*角度的正弦值
    圆周的大小,由所在圆的半径R的大小来决定; 
            通过以上的公式我们就可以让摇杆在灰色圆形上做圆周运动,当然除此之外我们还要注意三点:
    1:做圆周运动的大小,应该跟灰色区域的半径相同;
    2:触屏事件中应该首先判定用户触屏的位置是否在灰色区域中,如果不在,我们就应该获取摇杆与触屏点的角度然后获取摇杆应该在圆周运动上的XY坐标;如果在,就没有处理了,只要将摇杆位置随着用户点击位置就好了;
    3:在触屏事件中,当用户手指离开屏幕后,应该让摇杆的位置恢复到初始的位置状态; 
     下面是整个项目的MySurfaceView中全部代码:
[java] view plaincopy
  1. package com.example.test;  
  2.   
  3. import android.content.Context;  
  4. import android.content.Intent;  
  5. import android.graphics.Canvas;  
  6. import android.graphics.Color;  
  7. import android.graphics.Paint;  
  8. import android.util.Log;  
  9. import android.view.MotionEvent;  
  10. import android.view.SurfaceHolder;  
  11. import android.view.SurfaceView;  
  12. import android.view.SurfaceHolder.Callback;  
  13. import android.view.WindowManager;  
  14.   
  15. public class MySurfaceView extends SurfaceView implements Callback, Runnable {  
  16.   
  17.     private Thread th;  
  18.     private SurfaceHolder sfh;  
  19.     private Canvas canvas;  
  20.     private Paint paint;  
  21.     private boolean flag;  
  22.         private Context context;  
  23.       
  24.     WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);  
  25.     int width = wm.getDefaultDisplay().getWidth();  
  26.     int height = wm.getDefaultDisplay().getHeight();  
  27.       
  28.     // 固定摇杆背景圆形的X,Y坐标以及半径  
  29.     private int RockerCircleX = width/2;  
  30.     private int RockerCircleY = height/2;  
  31.     private int RockerCircleR = 100;  
  32.     // 摇杆的X,Y坐标以及摇杆的半径  
  33.     private float SmallRockerCircleX = width/2;  
  34.     private float SmallRockerCircleY = height/2;  
  35.     private float SmallRockerCircleR = 40;  
  36.   
  37.     public MySurfaceView(Context context) {  
  38.         super(context);  
  39.         this.context=context;  
  40.         Log.v("构造方法""MySurfaceView");  
  41.         this.setKeepScreenOn(true);  
  42.         sfh = this.getHolder();  
  43.         sfh.addCallback(this);  
  44.         paint = new Paint();  
  45.         paint.setAntiAlias(true);  
  46.         setFocusable(true);  
  47.         setFocusableInTouchMode(true);  
  48.     }  
  49.   
  50.     public void surfaceCreated(SurfaceHolder holder) {  
  51.         th = new Thread(this);  
  52.         flag = true;  
  53.         th.start();  
  54.     }  
  55.   
  56.     /*** 
  57.      * 得到两点之间的弧度 
  58.      */  
  59.     public double getRad(float px1, float py1, float px2, float py2) {  
  60.           
  61.         float x = px2 - px1;// 得到两点X的距离  
  62.         float y = py1 - py2;// 得到两点Y的距离   
  63.         float xie = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));// 算出斜边长   
  64.         float cosAngle = x / xie;// 得到这个角度的余弦值(通过三角函数中的定理 :邻边/斜边=角度余弦值)   
  65.         float rad = (float) Math.acos(cosAngle);// 通过反余弦定理获取到其角度的弧度   
  66.         if (py2 < py1) {// 注意:当触屏的位置Y坐标<摇杆的Y坐标我们要取反值-0~-180  
  67.             rad = -rad;  
  68.         }  
  69.         return rad;  
  70.     }  
  71.   
  72.     @Override  
  73.     public boolean onTouchEvent(MotionEvent event) {  
  74.         if (event.getAction() == MotionEvent.ACTION_DOWN  
  75.                 || event.getAction() == MotionEvent.ACTION_MOVE) {  
  76.             // 当触屏区域不在活动范围内  
  77.             if (Math.sqrt(Math.pow((RockerCircleX - (int) event.getX()), 2)  
  78.                     + Math.pow((RockerCircleY - (int) event.getY()), 2)) >= RockerCircleR) {  
  79.                 // 得到摇杆与触屏点所形成的角度  
  80.                 double tempRad = getRad(RockerCircleX, RockerCircleY,  
  81.                         event.getX(), event.getY());  
  82.                 // 保证内部小圆运动的长度限制  
  83.                 System.out.println(tempRad);  
  84.                 getXY(RockerCircleX, RockerCircleY, RockerCircleR, tempRad);  
  85.                 if(tempRad>=1.2&&tempRad<=1.8){  
  86.                       
  87.                     Intent intent=new Intent(context,TestActivity.class);  
  88.                     context.startActivity(intent);  
  89.                 }else if(tempRad>=-1.8&&tempRad<=-1.2){  
  90.                     Intent intent=new Intent(context,TestActivity2.class);  
  91.                     context.startActivity(intent);  
  92.                 }  
  93.             } else {// 如果小球中心点小于活动区域则随着用户触屏点移动即可  
  94.                 SmallRockerCircleX = (int) event.getX();  
  95.                 SmallRockerCircleY = (int) event.getY();  
  96.             }  
  97.         } else if (event.getAction() == MotionEvent.ACTION_UP) {  
  98.             // 当释放按键时摇杆要恢复摇杆的位置为初始位置  
  99.             SmallRockerCircleX = width/2;  
  100.             SmallRockerCircleY = height/2;  
  101.         }  
  102.         return true;  
  103.     }  
  104.   
  105.     /** 
  106.      *      圆周运动的旋转点 
  107.      * @param centerX 旋转点X        
  108.      * @param centerY  旋转点Y           
  109.      * @param rad 旋转的弧度            
  110.      */  
  111.     public void getXY(float centerX, float centerY, float R, double rad) {  
  112.         // 获取圆周运动的X坐标  
  113.         SmallRockerCircleX = (float) (R * Math.cos(rad)) + centerX;  
  114.         // 获取圆周运动的Y坐标  
  115.         SmallRockerCircleY = (float) (R * Math.sin(rad)) + centerY;  
  116.     }  
  117.   
  118.     public void draw() {  
  119.         try {  
  120.             canvas = sfh.lockCanvas();  
  121.             canvas.drawColor(Color.CYAN);// 设置透明度         
  122.             paint.setColor(Color.WHITE);// 设置摇杆背景色        
  123.             canvas.drawCircle(RockerCircleX, RockerCircleY, RockerCircleR,  
  124.                     paint);//绘制摇杆背景  
  125.             paint.setColor(Color.GREEN);//设置摇杆颜色          
  126.             canvas.drawCircle(SmallRockerCircleX, SmallRockerCircleY,  
  127.                     SmallRockerCircleR, paint);// 绘制摇杆  
  128.         } catch (Exception e) {  
  129.         } finally {  
  130.             try {  
  131.                 if (canvas != null)  
  132.                     sfh.unlockCanvasAndPost(canvas);  
  133.             } catch (Exception e2) {  
  134.   
  135.             }  
  136.         }  
  137.     }  
  138.   
  139.     public void run() {  
  140.         while (flag) {  
  141.             draw();  
  142.             try {  
  143.                 Thread.sleep(50);  
  144.             } catch (Exception ex) {  
  145.             }  
  146.         }  
  147.     }  
  148.   
  149.     public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  150.             int height) {  
  151.         Log.v("MySurfaceView""surfaceChanged");  
  152.     }  
  153.   
  154.     public void surfaceDestroyed(SurfaceHolder holder) {  
  155.         flag = false;  
  156.         Log.v("MySurfaceView""surfaceDestroyed");  
  157.     }  
  158. }  
MainActivity代码如下:

[java] view plaincopy
  1. <pre name="code" class="java">com.example.test;</pre>import android.app.Activity;import android.os.Bundle;import android.view.Window;import android.view.WindowManager;public class MainActivity extends Activity {/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);this.requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(new MySurfaceView(MainActivity.this));}}  
另外还有2个TestActivity,很简单就是用来显示测试的,没有什么界面。至此,这个Demo就介绍到这里,感兴趣的朋友可以继续美化一下UI来使用。
原创粉丝点击