当前位置: 代码迷 >> Android >> 小弟我的Android进阶之旅->Android利用Sensor(传感器)实现水平仪功能的小例
  详细解决方案

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

热度:268   发布时间:2016-04-28 00:06:36.0
我的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);	}	@Override	protected 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;	@Override	public void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentView(R.layout.main);		// 获取水平仪的主组件		show = (MyView) findViewById(R.id.show);		// 获取传感器管理服务		mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);	}	@Override	public void onResume() {		super.onResume();		// 为系统的方向传感器注册监听器		mSensorManager.registerListener(this,				mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),				SensorManager.SENSOR_DELAY_GAME);	}	@Override	protected void onPause() {		// 取消注册		mSensorManager.unregisterListener(this);		super.onPause();	}	@Override	protected void onStop() {		// 取消注册		mSensorManager.unregisterListener(this);		super.onStop();	}	@Override	public void onAccuracyChanged(Sensor sensor, int accuracy) {	}	@Override	public 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、Y		int bubbleCx = x + show.bubble.getWidth() / 2;		int bubbleCy = y + show.bubble.getWidth() / 2;		// 计算水平仪仪表盘的圆心座标X、Y		int 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-sdk		android: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

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

  

版权声明:本文为博主原创文章,未经博主允许不得转载。

  相关解决方案