這里介紹的水平儀,指的是比較傳統的氣泡水平儀,在一個透明圓盤內充滿液體,液體中留有一個氣泡,當一端翹起時,該氣泡就會浮向翹起的一端。
利用方向傳感器返回的第一個參數,實現了一個指南針小應用。
我的Android進階之旅------>Android利用Sensor(傳感器)實現指南針功能
接下來,我們利用返回的第二、三個參數實現該水平儀。因為第二個參數,反映底部翹起的角度(當頂部翹起時為負值),第三個參數可以反映右側翹起的角度(當左側翹起時為負值)。根據這兩個角度就可以開發水平儀,實現手機哪端翹起,氣泡就浮向哪端,這也是水平儀的實現思想。本實例來自于《瘋狂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:請在真機環境下運行此程序,如果在模擬器下運行,可能沒效果。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。