热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android虚拟摇杆绘制

首先附上效果图1、自定义RockerView[java]viewplaincopypackagecom.example.rocker;importandroid.content.C

首先附上效果图


1、自定义RockerView

[java] view plaincopy
  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(00);  
  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.         //注意&#xff1a;当触屏的位置Y坐标<摇杆的Y坐标我们要取反值-0~-180  
  145.         if (py2 < py1) {  
  146.             rad &#61; -rad;  
  147.         }  
  148.         return rad;  
  149.     }  
  150.       
  151.     /** 
  152.      *  
  153.      * &#64;param R  圆周运动的旋转点 
  154.      * &#64;param centerX 旋转点X 
  155.      * &#64;param centerY 旋转点Y 
  156.      * &#64;param rad 旋转的弧度 
  157.      */  
  158.     public void getXY(float centerX, float centerY, float R, double rad) {  
  159.         //获取圆周运动的X坐标   
  160.         mRockerBtn_X &#61; (float) (R * Math.cos(rad)) &#43; centerX;  
  161.         //获取圆周运动的Y坐标  
  162.         mRockerBtn_Y &#61; (float) (R * Math.sin(rad)) &#43; centerY;  
  163.     }  
  164.       
  165.     RockerChangeListener mRockerChangeListener &#61; null;  
  166.     public void setRockerChangeListener(RockerChangeListener rockerChangeListener) {  
  167.         mRockerChangeListener &#61; rockerChangeListener;  
  168.     }  
  169.     public interface RockerChangeListener {  
  170.         public void report(float x, float y);  
  171.     }  
  172. }  


2、布局文件中添加RockerView

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


3、MainActiviy中使用RockerView

[java] view plaincopy
  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 &#61; "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.     &#64;Override  
  27.     protected void onCreate(Bundle savedInstanceState) {  
  28.         super.onCreate(savedInstanceState);  
  29.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  30.         getWindow().setFlags(  
  31.                 WindowManager.LayoutParams.FLAG_FULLSCREEN  
  32.                         | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,  
  33.                 WindowManager.LayoutParams.FLAG_FULLSCREEN  
  34.                         | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);// 设置全屏  
  35.                                                                             // ,  
  36.                                                                             // 屏幕长亮  
  37.         setContentView(R.layout.activity_main);  
  38.   
  39.         DisplayMetrics dm &#61; getResources().getDisplayMetrics();  
  40.         screenWidth &#61; dm.widthPixels;  
  41.         screenHeight &#61; dm.heightPixels;  
  42.   
  43.         rockerView1 &#61; (RockerView) findViewById(R.id.rockerView1);  
  44.         rockerView2 &#61; (RockerView) findViewById(R.id.rockerView2);  
  45.   
  46.         rockerView1.setRockerChangeListener(new RockerView.RockerChangeListener() {  
  47.   
  48.                     &#64;Override  
  49.                     public void report(float x, float y) {  
  50.                         // TODO Auto-generated method stub  
  51.                         // doLog(x &#43; "/" &#43; y);  
  52.                         setLayout(rockerView2, (int)x, (int)y);  
  53.                     }  
  54.                 });  
  55.   
  56.         rockerView2.setRockerChangeListener(new RockerView.RockerChangeListener() {  
  57.   
  58.                     &#64;Override  
  59.                     public void report(float x, float y) {  
  60.                         // TODO Auto-generated method stub  
  61.                         // doLog(x &#43; "/" &#43; y);  
  62.                         setLayout(rockerView1, (int)x, (int)y);  
  63.                     }  
  64.                 });  
  65.     }  
  66.   
  67.     public void setLayout(View v, int dx, int dy) {  
  68.         int left &#61; v.getLeft() &#43; dx;  
  69.         int top &#61; v.getTop() &#43; dy;  
  70.         int right &#61; v.getRight() &#43; dx;  
  71.         int bottom &#61; v.getBottom() &#43; dy;  
  72.         if (left < 0) {  
  73.             left &#61; 0;  
  74.             right &#61; left &#43; v.getWidth();  
  75.         }  
  76.         if (right > screenWidth) {  
  77.             right &#61; screenWidth;  
  78.             left &#61; right - v.getWidth();  
  79.         }  
  80.         if (top < 0) {  
  81.             top &#61; 0;  
  82.             bottom &#61; top &#43; v.getHeight();  
  83.         }  
  84.         if (bottom > screenHeight) {  
  85.             bottom &#61; screenHeight;  
  86.             top &#61; bottom - v.getHeight();  
  87.         }  
  88.         v.layout(left, top, right, bottom);  
  89.     }  
  90. }  



如下是代码下载地址

http://download.csdn.net/detail/qwjun/9282127


推荐阅读
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • MPLS VP恩 后门链路shamlink实验及配置步骤
    本文介绍了MPLS VP恩 后门链路shamlink的实验步骤及配置过程,包括拓扑、CE1、PE1、P1、P2、PE2和CE2的配置。详细讲解了shamlink实验的目的和操作步骤,帮助读者理解和实践该技术。 ... [详细]
author-avatar
LOKYIP2012_862
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有