我的Android进阶之旅------Android利用Sensor(传感器)实现水平仪功能的小例

   

   这里介绍的水平仪,指的是比较传统的气泡水平仪,在一个透明圆盘内充满液体,液体中留有一个气泡,当一端翘起时,该气泡就会浮向翘起的一端。

   利用方向传感器返回的第一个参数,实现了一个指南针小应用。
   我的Android进阶之旅------>Android利用Sensor(传感器)实现指南针功能
 (地址:http://blog.csdn.net/ouyang_peng/article/details/8801204)
   接下来,我们利用返回的第二、三个参数实现该水平仪。因为第二个参数,反映底部翘起的角度(当顶部翘起时为负值),第三个参数可以反映右侧翘起的角度(当左侧翘起时为负值)。根据这两个角度就可以开发水平仪,实现手机哪端翘起,气泡就浮向哪端,这也是水平仪的实现思想。本实例来自于《疯狂Android讲义》
先来看下运行效果:

该程序自定义了一个View,用来绘制透明圆盘和气泡,其中气泡的位置会动态改变。自定义View代码如下:

MyView.java
package org.crazyit.sensor;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;public class MyView extends View {// 定义水平仪仪表盘图片Bitmap back;// 定义水平仪中的气泡图标Bitmap bubble;// 定义水平仪中气泡 的X、Y座标int bubbleX, bubbleY;public MyView(Context context, AttributeSet attrs) {super(context, attrs);// 加载水平仪图片和气泡图片back = BitmapFactory.decodeResource(getResources(), R.drawable.back);bubble = BitmapFactory.decodeResource(getResources(), R.drawable.bubble);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 绘制水平仪表盘图片canvas.drawBitmap(back, 0, 0, null);// 根据气泡座标绘制气泡canvas.drawBitmap(bubble, bubbleX, bubbleY, null);}
}
布局文件 main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="#fff">
<org.crazyit.sensor.MyView  android:id="@+id/show"android:layout_width="fill_parent" android:layout_height="fill_parent"
/>
</FrameLayout>
bubble.png    

back.png   


Gradienter.java


package org.crazyit.sensor;import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;public class Gradienter extends Activity implements SensorEventListener {// 定义水平仪的仪表盘MyView show;// 定义水平仪能处理的最大倾斜角,超过该角度,气泡将直接在位于边界。int MAX_ANGLE = 30;// 定义Sensor管理器SensorManager mSensorManager;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);// 获取水平仪的主组件show = (MyView) findViewById(R.id.show);// 获取传感器管理服务mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);}@Overridepublic void onResume() {super.onResume();// 为系统的方向传感器注册监听器mSensorManager.registerListener(this,mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),SensorManager.SENSOR_DELAY_GAME);}@Overrideprotected void onPause() {// 取消注册mSensorManager.unregisterListener(this);super.onPause();}@Overrideprotected void onStop() {// 取消注册mSensorManager.unregisterListener(this);super.onStop();}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}@Overridepublic void onSensorChanged(SensorEvent event) {float[] values = event.values;// 获取触发event的传感器类型int sensorType = event.sensor.getType();switch (sensorType) {case Sensor.TYPE_ORIENTATION:// 获取与Y轴的夹角float yAngle = values[1];// 获取与Z轴的夹角float zAngle = values[2];// 气泡位于中间时(水平仪完全水平),气泡的X、Y座标int x = (show.back.getWidth() - show.bubble.getWidth()) / 2;int y = (show.back.getHeight() - show.bubble.getHeight()) / 2;// 如果与Z轴的倾斜角还在最大角度之内if (Math.abs(zAngle) <= MAX_ANGLE) {// 根据与Z轴的倾斜角度计算X座标的变化值(倾斜角度越大,X座标变化越大)int deltaX = (int) ((show.back.getWidth() - show.bubble.getWidth()) / 2 * zAngle / MAX_ANGLE);x += deltaX;}// 如果与Z轴的倾斜角已经大于MAX_ANGLE,气泡应到最左边else if (zAngle > MAX_ANGLE) {x = 0;}// 如果与Z轴的倾斜角已经小于负的MAX_ANGLE,气泡应到最右边else {x = show.back.getWidth() - show.bubble.getWidth();}// 如果与Y轴的倾斜角还在最大角度之内if (Math.abs(yAngle) <= MAX_ANGLE) {// 根据与Y轴的倾斜角度计算Y座标的变化值(倾斜角度越大,Y座标变化越大)int deltaY = (int) ((show.back.getHeight() - show.bubble.getHeight()) / 2 * yAngle / MAX_ANGLE);y += deltaY;}// 如果与Y轴的倾斜角已经大于MAX_ANGLE,气泡应到最下边else if (yAngle > MAX_ANGLE) {y = show.back.getHeight() - show.bubble.getHeight();}// 如果与Y轴的倾斜角已经小于负的MAX_ANGLE,气泡应到最右边else {y = 0;}// 如果计算出来的X、Y座标还位于水平仪的仪表盘内,更新水平仪的气泡座标if (isContain(x, y)) {show.bubbleX = x;show.bubbleY = y;}// 通知系统重回MyView组件show.postInvalidate();break;}}// 计算x、y点的气泡是否处于水平仪的仪表盘内private boolean isContain(int x, int y) {// 计算气泡的圆心座标X、Yint bubbleCx = x + show.bubble.getWidth() / 2;int bubbleCy = y + show.bubble.getWidth() / 2;// 计算水平仪仪表盘的圆心座标X、Yint backCx = show.back.getWidth() / 2;int backCy = show.back.getWidth() / 2;// 计算气泡的圆心与水平仪仪表盘的圆心之间的距离。double distance = Math.sqrt((bubbleCx - backCx) * (bubbleCx - backCx)+ (bubbleCy - backCy) * (bubbleCy - backCy));// 若两个圆心的距离小于它们的半径差,即可认为处于该点的气泡依然位于仪表盘内if (distance < (show.back.getWidth() - show.bubble.getWidth()) / 2) {return true;} else {return false;}}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="org.crazyit.sensor"android:versionCode="1"android:versionName="1.0"><uses-sdkandroid:minSdkVersion="10"android:targetSdkVersion="17" /><application android:icon="@drawable/ic_launcher" android:label="@string/app_name"><activity android:name=".Gradienter"android:label="@string/app_name"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
</manifest> 

PS:请在真机环境下运行此程序,如果在模拟器下运行,可能没效果

 

                            ====================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址:http://blog.csdn.net/ouyang_peng

====================================================================================


转载于:https://www.cnblogs.com/ouyangpeng/p/8538056.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400026.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【linux命令总结】——后续用到的内容持续补充和更新

比如说&#xff1a;某个文件是go文件&#xff0c;名字叫做 Hello.go 1、通过后台运行某个程序&#xff0c;将结果输出到某个文件&#xff0c; 如果是直接运行go程序&#xff1a;go run Hello.go 后台运行&#xff1a;nohup go run Hello.go & &#xff0c;然后就会将结果输…

【Jetson Nano学习笔记】2. ORB-SLAM3及ZED 2i驱动安装

目录ZED 2i驱动安装安装驱动自测ROS测试zed2i.launchrostopic listrosnode listdisplay_zed2i.launchzed_rtabmap.launchORB-SLAM3安装OpenCV 3安装Glew安装Pangolin安装boost安装Eigen 3安装OpenGL安装openssl安装ORB-SLAM3建立swap准备编译编译关闭swap平台&#xff1a;Jetso…

给超链接(a标签)加onclick事件

<a onclick"alert(1)">超链接1</a><br> <a href"#" onclick"alert(2)">超链接2</a> <br> <a href"javascript:alert(3)">超链接3</a>

proj1088

滑雪Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 69608 Accepted: 25669Description Michael喜欢滑雪百这并不奇怪&#xff0c; 因为滑雪的确很刺激。可是为了获得速度&#xff0c;滑的区域必须向下倾斜&#xff0c;而且当你滑到坡底&#xff0c;你不得不再次走…

【Jetson Nano学习笔记】3. ORB-SLAM3运行双目Demo(ZED 2i)

目录修改zed-ros-wrapper的参数双目测试平台&#xff1a;Jetson Nano 系统版本&#xff1a;4.6.1 参考资料&#xff1a; zed-ros-wrapper —— ROS Wiki ZED 相机 && ORB-SLAM2安装环境配置与ROS下的调试 —— 李小铭 又一遍……ORB_SLAM2ZED相机(SDK2.2.1)CUDA9.0ROS…

PyCharm设置自动换行

在使用PyCharm码代码的时候&#xff0c;有些单行的代码比较长&#xff0c;经常需要手动拉动滚动条。 辣么怎么设置自动换行呢&#xff1f;&#xff1f; 敲黑板 在这里给大家介绍两种方式&#xff1a; 1、如果你需要频繁在【自动换行/非自动换行】模式中切换 那就需要设置一个顺…

邮件服务

http://linuxsogood.org/1121.html/comment-page-1 转载于:https://www.cnblogs.com/saolv/p/7440536.html

MySQL数据库和ACID模型

2019独角兽企业重金招聘Python工程师标准>>> ACID模型是一组强调高可靠性的数据库系统设计原则。InnoDB存储引擎坚持ACID原则&#xff0c;确保即使在软件崩溃甚至是硬件故障的情况下&#xff0c;数据也不会损坏。当你需要依赖兼容ACID原则的业务时&#xff0c;你不必…

MFC中SQLite数据库的使用

1打开数据库 BOOL playDlg::openData() { WCHAR a[100]; CString path; path m_exePathL"sentence_making\\FROG.db"; memcpy(a,path,sizeof(a)); int nRet sqlite3_open16((const char *)a,&pSQLite); // 链接到数据库&#xff0c;如果成功&#xff0c;数据…

【Jetson Nano学习笔记】4. python 3编译bridge

目录使用python3编译boostconsole_bridgepython3bridge平台&#xff1a;Jetson Nano 系统版本&#xff1a;4.6.1 参考资料&#xff1a; How to setup ROS with Python 3 Unable to use cv_bridge with ROS Kinetic and Python3 CMake Error &#xff1a;Could not find a pac…

Python作用域

Python是静态作用域&#xff0c;也就是说在Python中&#xff0c;变量的作用域源于它在代码中的位置。与C语言有一些类似&#xff0c;与C语言比起来还有一些需要注意的地方。 现在的Python支持4种作用域&#xff0c;"LEGB" L(local)&#xff1a;局部作用域&#xff1b…

解决flask端口被占用的问题

2019.04.11 实测&#xff1a; 只要停止程序&#xff0c;再运行&#xff0c;就可以了 问题提示&#xff1a;socket.error:[Errno 48] Address already in use 在编辑flask代码时&#xff0c;如果没有关闭flask的程序&#xff0c;默认的5000端口一直被占用。 再次运行的时候&am…

使用模板来解决接口继承问题

一.定义2个有继承关系的接口 struct IA {virtual void Test1()0; };struct IB:public IA {virtual void Test2()0; };二.定义2个类来实现 class A:public IA {virtual void Test1() {} };class B:public IB { public:virtual void Test2() {} };类B将无法使用,必须重新实现IA的…

python time模块详解

2019独角兽企业重金招聘Python工程师标准>>> python time模块详解 分类&#xff1a; python2009-03-28 23:35 89831人阅读 评论(9) 收藏 举报 pythonstructstringdstimportdate python 的内嵌time模板翻译及说明 一、简介 time模块提供各种操作时间的函数 说明&am…

单例写法 转

如何正确地写出单例模式 1.懒汉式&#xff0c;线程不安全 这段代码简单明了&#xff0c;而且使用了懒加载模式&#xff0c;但是却存在致命的问题。当有多个线程并行调用 getInstance() 的时候&#xff0c;就会创建多个实例。也就是说在多线程下不能正常工作 public class Singl…

【RK3399Pro学习笔记】十九、在ROS中点亮LED灯

目录创建ROS工作空间创建ROS功能包CSysFs方式&#xff08;需root&#xff09;源文件blink.cppgpiolib.cpp头文件gpiolib.hCMakeLists.txt运行代码调用shell命令方式&#xff08;无需root&#xff09;源文件blink.cppCMakeLists.txt运行代码平台&#xff1a;华硕 Thinker Edge R…

opencv中的Mat类型

Mat类型主要是跟matlab中的数据类型一样。故用起来很方便。 Mat最大的优势跟STL很相似&#xff0c;都是对内存进行动态的管理&#xff0c;不需要之前用户手动的管理内存&#xff0c;对于一些大型的开发&#xff0c;有时候投入的lpImage内存管理的时间甚至比关注算法实现的时间还…

C/C++与内存相关的函数

C语言的标准函数库与内存管理有关的函数从功能上分为两类:一类是系统对内存操作的函数,例如,读内存的函数、写内存函数,如从指定地址向内存写一个字节,一个字或向内存读一个字节或一个字操作;另一类是供用户动态使用内存的函数,例如,分配C程序一块存储区,并将该区清零函数; 1.动…

flask jinja2 如何遍历新闻列表

NEWS_DICT [{"newstitle": "新闻1", "url": "newsurl1"},{"newstitle": "新闻2", "url": "newsurl2"},{"newstitle": "新闻3", "url": "newsurl3"…

hihocoder [Offer收割]编程练习赛24

比赛https://hihocoder.com/contest/offers24/problems 应该能拿到个鼠标垫 舒服了 这个oj体验好差&#xff0c;每次都要先因为选错语言CE一发&#xff0c;而且刷新之后还是默认GCC A ⼩Hi的钟表 算秒数&#xff0c;算角度&#xff0c;注意180以内&#xff0c;所以大于180之后拿…