牛骨文教育服务平台(让学习变的简单)
博文笔记

android 虚拟摇杆绘制

创建时间:2017-07-20 投稿人: 浏览次数:543

首先附上效果图


1、自定义RockerView

[java] view plain copy
  1. package com.example.rocker;  
  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.PointF;  
  8. import android.graphics.Rect;  
  9. import android.util.AttributeSet;  
  10. import android.util.Log;  
  11. import android.view.MotionEvent;  
  12. import android.view.View;  
  13. import android.view.ViewTreeObserver;  
  14. import android.view.ViewTreeObserver.OnPreDrawListener;  
  15.   
  16. public class RockerView extends View {  
  17.   
  18.     //固定摇杆背景圆形的X,Y坐标以及半径  
  19.     private float mRockerBg_X;  
  20.     private float mRockerBg_Y;  
  21.     private float mRockerBg_R;  
  22.     //摇杆的X,Y坐标以及摇杆的半径  
  23.     private float mRockerBtn_X;  
  24.     private float mRockerBtn_Y;  
  25.     private float mRockerBtn_R;  
  26.     private Bitmap mBmpRockerBg;  
  27.     private Bitmap mBmpRockerBtn;  
  28.       
  29.     private PointF mCenterPoint;  
  30.       
  31.     public RockerView(Context context, AttributeSet attrs) {  
  32.         super(context, attrs);  
  33.         // TODO Auto-generated constructor stub  
  34.         // 获取bitmap  
  35.         mBmpRockerBg = BitmapFactory.decodeResource(context.getResources(), R.drawable.rocker_bg);  
  36.         mBmpRockerBtn = BitmapFactory.decodeResource(context.getResources(), R.drawable.rocker_btn);  
  37.           
  38.         getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {  
  39.               
  40.             // 调用该方法时可以获取view实际的宽getWidth()和高getHeight()  
  41.             @Override  
  42.             public boolean onPreDraw() {  
  43.                 // TODO Auto-generated method stub  
  44.                 getViewTreeObserver().removeOnPreDrawListener(this);   
  45.                   
  46.                 Log.e("RockerView", getWidth() + "/" +  getHeight());  
  47.                 mCenterPoint = new PointF(getWidth() / 2, getHeight() / 2);  
  48.                 mRockerBg_X = mCenterPoint.x;  
  49.                 mRockerBg_Y = mCenterPoint.y;  
  50.                   
  51.                 mRockerBtn_X = mCenterPoint.x;  
  52.                 mRockerBtn_Y = mCenterPoint.y;  
  53.                   
  54.                 float tmp_f = mBmpRockerBg.getWidth() / (float)(mBmpRockerBg.getWidth() + mBmpRockerBtn.getWidth());  
  55.                 mRockerBg_R = tmp_f * getWidth() / 2;  
  56.                 mRockerBtn_R = (1.0f - tmp_f)* getWidth() / 2;  
  57.                   
  58.                 return true;  
  59.             }  
  60.         });  
  61.       
  62.           
  63.         new Thread(new Runnable() {  
  64.               
  65.             @Override  
  66.             public void run() {  
  67.                 // TODO Auto-generated method stub  
  68.                 while(true){  
  69.                       
  70.                     //系统调用onDraw方法刷新画面  
  71.                     RockerView.this.postInvalidate();  
  72.                       
  73.                     try {  
  74.                         Thread.sleep(100);  
  75.                     } catch (InterruptedException e) {  
  76.                         // TODO Auto-generated catch block  
  77.                         e.printStackTrace();  
  78.                     }  
  79.                 }  
  80.             }  
  81.         }).start();  
  82.     }  
  83.       
  84.     @Override  
  85.     protected void onDraw(Canvas canvas) {  
  86.         // TODO Auto-generated method stub  
  87.         super.onDraw(canvas);  
  88.         canvas.drawBitmap(mBmpRockerBg, null,   
  89.                 new Rect((int)(mRockerBg_X - mRockerBg_R),   
  90.                         (int)(mRockerBg_Y - mRockerBg_R),   
  91.                         (int)(mRockerBg_X + mRockerBg_R),   
  92.                         (int)(mRockerBg_Y + mRockerBg_R)),   
  93.                 null);  
  94.         canvas.drawBitmap(mBmpRockerBtn, null,   
  95.                 new Rect((int)(mRockerBtn_X - mRockerBtn_R),   
  96.                         (int)(mRockerBtn_Y - mRockerBtn_R),   
  97.                         (int)(mRockerBtn_X + mRockerBtn_R),   
  98.                         (int)(mRockerBtn_Y + mRockerBtn_R)),   
  99.                 null);  
  100.     }  
  101.       
  102.     @Override  
  103.     public boolean onTouchEvent(MotionEvent event) {  
  104.         // TODO Auto-generated method stub  
  105.         if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {  
  106.             // 当触屏区域不在活动范围内  
  107.             if (Math.sqrt(Math.pow((mRockerBg_X - (int) event.getX()), 2) + Math.pow((mRockerBg_Y - (int) event.getY()), 2)) >= mRockerBg_R) {  
  108.                 //得到摇杆与触屏点所形成的角度  
  109.                 double tempRad = getRad(mRockerBg_X, mRockerBg_Y, event.getX(), event.getY());  
  110.                 //保证内部小圆运动的长度限制  
  111.                 getXY(mRockerBg_X, mRockerBg_Y, mRockerBg_R, tempRad);  
  112.             } else {//如果小球中心点小于活动区域则随着用户触屏点移动即可  
  113.                 mRockerBtn_X = (int) event.getX();  
  114.                 mRockerBtn_Y = (int) event.getY();  
  115.             }  
  116.             if(mRockerChangeListener != null) {  
  117.                 mRockerChangeListener.report(mRockerBtn_X - mCenterPoint.x, mRockerBtn_Y - mCenterPoint.y);  
  118.             }  
  119.         } else if (event.getAction() == MotionEvent.ACTION_UP) {  
  120.             //当释放按键时摇杆要恢复摇杆的位置为初始位置  
  121.             mRockerBtn_X = mCenterPoint.x;  
  122.             mRockerBtn_Y = mCenterPoint.y;  
  123.             if(mRockerChangeListener != null) {  
  124.                 mRockerChangeListener.report(0, 0);  
  125.             }  
  126.         }  
  127.         return true;  
  128.     }  
  129.       
  130.     /*** 
  131.      * 得到两点之间的弧度 
  132.      */  
  133.     public double getRad(float px1, float py1, float px2, float py2) {  
  134.         //得到两点X的距离  
  135.         float x = px2 - px1;  
  136.         //得到两点Y的距离  
  137.         float y = py1 - py2;  
  138.         //算出斜边长  
  139.         float xie = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));  
  140.         //得到这个角度的余弦值(通过三角函数中的定理 :邻边/斜边=角度余弦值)  
  141.         float cosAngle = x / xie;  
  142.         //通过反余弦定理获取到其角度的弧度  
  143.         float rad = (float) Math.acos(cosAngle);  
  144.         //注意:当触屏的位置Y坐标<摇杆的Y坐标我们要取反值-0~-180  
  145.         if (py2 < py1) {  
  146.             rad = -rad;  
  147.         }  
  148.         return rad;  
  149.     }  
  150.       
  151.     /** 
  152.      *  
  153.      * @param R  圆周运动的旋转点 
  154.      * @param centerX 旋转点X 
  155.      * @param centerY 旋转点Y 
  156.      * @param rad 旋转的弧度 
  157.      */  
  158.     public void getXY(float centerX, float centerY, float R, double rad) {  
  159.         //获取圆周运动的X坐标   
  160.         mRockerBtn_X = (float) (R * Math.cos(rad)) + centerX;  
  161.         //获取圆周运动的Y坐标  
  162.         mRockerBtn_Y = (float) (R * Math.sin(rad)) + centerY;  
  163.     }  
  164.       
  165.     RockerChangeListener mRockerChangeListener = null;  
  166.     public void setRockerChangeListener(RockerChangeListener rockerChangeListener) {  
  167.         mRockerChangeListener = rockerChangeListener;  
  168.     }  
  169.     public interface RockerChangeListener {  
  170.         public void report(float x, float y);  
  171.     }  
  172. }  
2、布局文件中添加RockerView

[html] view plain copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="#ff4f4f4f"  
  6.     tools:context=".MainActivity" >  
  7.   
  8.     <com.example.rocker.RockerView   
  9.         android:id="@+id/rockerView1"  
  10.         android:layout_width="120dp"  
  11.         android:layout_height="120dp"  
  12.         android:layout_alignParentBottom="true"  
  13.         android:layout_marginLeft="20dp"  
  14.         android:layout_marginBottom="20dp"/>  
  15.       
  16.     <com.example.rocker.RockerView   
  17.         android:id="@+id/rockerView2"  
  18.         android:layout_width="120dp"  
  19.         android:layout_height="120dp"  
  20.         android:layout_alignParentBottom="true"  
  21.         android:layout_alignParentRight="true"  
  22.         android:layout_marginRight="20dp"  
  23.         android:layout_marginBottom="20dp"/>  
  24.   
  25. </RelativeLayout>  


3、MainActiviy中使用RockerView

[java] view plain copy
  1. package com.example.rocker;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.util.DisplayMetrics;  
  6. import android.util.Log;  
  7. import android.view.View;  
  8. import android.view.ViewGroup.MarginLayoutParams;  
  9. import android.view.Window;  
  10. import android.view.WindowManager;  
  11. import android.widget.RelativeLayout;  
  12.   
  13. public class MainActivity extends Activity {  
  14.   
  15.     private static final String TAG = "MainActivity";  
  16.   
  17.     void doLog(String log) {  
  18.         Log.e(TAG, log);  
  19.     }  
  20.   
  21.     private RockerView rockerView1;  
  22.     private RockerView rockerView2;  
  23.     int screenWidth;  
  24.     int screenHeight;  
  25.   
  26.     @Override  
  27.     protected void onCreate(Bundle savedInstanceState) {  
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。