Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 利用Android傳感器開發水平儀

利用Android傳感器開發水平儀

編輯:關於Android編程

這裡介紹的水平儀,指的是比較傳統的氣泡水平儀,在一個透明圓盤內充滿液體,液體中留有一個氣泡,當一端翹起時,該氣泡就會浮向翹起的一端。   在上文中,利用方向傳感器返回的第一個參數,實現了一個指南針小應用。接下來,我們利用返回的第二、三個參數實現該水平儀。因為第二個參數,反映底部(或頂部)翹起的角度,第三個參數可以反映右側(或左側)翹起的角度。根據這兩個角度就可以開發水平儀,實現手機哪端翹起,氣泡就浮向哪端,這也是水平儀的實現思想。代碼如下:   Activity:    
package com.home.activity;  
  
import android.app.Activity;  
import android.hardware.Sensor;  
import android.hardware.SensorEvent;  
import android.hardware.SensorEventListener;  
import android.hardware.SensorManager;  
import android.os.Bundle;  
  
import com.home.R;  
import com.home.view.MyView;  
  
public class MainActivity extends Activity implements SensorEventListener {  
    // 定義水平儀的儀表盤   
    private MyView view;  
    // 定義水平儀能處理的最大傾斜角,超過該角度,氣泡將直接位於邊界   
    private final int MAX_ANGLE = 30;  
    // 定義真機的Sensor管理器   
    private SensorManager mSensorManager;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        // 獲取水平儀的組件   
        view = (MyView) findViewById(R.id.main_myview);  
        // 獲取真機的傳感器管理服務   
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);  
    }  
  
    @Override  
    protected 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  
    public void onAccuracyChanged(Sensor sensor, int accuracy) {  
    }  
  
    @Override  
    public void onSensorChanged(SensorEvent event) {  
        float[] values = event.values;  
        // 真機上獲取觸發的傳感器類型   
        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 = (view.back.getWidth() - view.bubble.getWidth()) / 2;  
            int y = (view.back.getHeight() - view.bubble.getHeight()) / 2;  
            // 如果與z軸的傾斜角還在最大角度之內   
            if (Math.abs(zAngle) <= MAX_ANGLE) {  
                // 根據與z軸的傾斜角計算x坐標的變化值(傾斜角度越大,x坐標變化越大)   
                int deltaX = (int) ((view.back.getWidth() - view.bubble  
                        .getWidth()) / 2 * zAngle / MAX_ANGLE);  
                x += deltaX;  
            }  
            // 如果與z軸的傾斜角已經大於MAX_ANGLE,氣泡應到最左邊   
            else if (zAngle > MAX_ANGLE) {  
                x = 0;  
            }  
            // 如果與Z軸的傾斜角已經小於負的MAX_ANGLE,氣泡應到最右邊   
            else {  
                x = view.back.getWidth() - view.bubble.getWidth();  
            }  
            // 如果與Y軸的傾斜角還在最大角度之內   
            if (Math.abs(yAngle) <= MAX_ANGLE) {  
                // 根據與Y軸的傾斜角計算Y坐標的變化值(傾斜角度越大,Y坐標變化越大)   
                int deltaY = (int) ((view.back.getHeight() - view.bubble  
                        .getHeight()) / 2 * zAngle / MAX_ANGLE);  
                y += deltaY;  
            }  
            // 如果與Y軸的傾斜角已經大於MAX_ANGLE,氣泡應到最下邊   
            else if (yAngle > MAX_ANGLE) {  
                y = view.back.getHeight() - view.bubble.getHeight();  
            }  
            // 如果與Y軸的傾斜角已經小於負的MAX_ANGLE,氣泡應到最右邊   
            else {  
                y = 0;  
            }  
            // 如果計算出來的X、Y坐標還位於水平儀的儀表盤內,更新水平儀的氣泡坐標   
            if (isContain(x, y)) {  
                view.bubbleX = x;  
                view.bubbleY = y;  
            }  
            // 通知系統重繪MyView組件   
            view.postInvalidate();  
            break;  
        }  
    }  
  
    // 計算X、Y點的氣泡是否處於水平儀的儀表盤內   
    private boolean isContain(int x, int y) {  
        // 計算氣泡的圓心坐標X、Y   
        int bubbleCx = x + view.bubble.getWidth() / 2;  
        int bubbleCy = y + view.bubble.getHeight() / 2;  
        // 計算水平儀儀表盤的圓心坐標X、Y   
        int backCx = view.back.getWidth() / 2;  
        int backCy = view.back.getHeight() / 2;  
        // 計算氣泡的圓心與水平儀儀表盤的圓心之間的距離   
        double distance = Math.sqrt((bubbleCx - backCx) * (bubbleCx - backCx)  
                + (bubbleCy - backCy) * (bubbleCy - backCy));  
        // 若兩個圓心的距離小於它們的半徑差,即可認為處於該店的氣泡依然位於儀表盤內   
        if (distance < (view.back.getWidth() - view.bubble.getWidth()) / 2) {  
            return true;  
        } else {  
            return false;  
        }  
    }  
}  

package com.home.activity;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;

import com.home.R;
import com.home.view.MyView;

public class MainActivity extends Activity implements SensorEventListener {
// 定義水平儀的儀表盤
private MyView view;
// 定義水平儀能處理的最大傾斜角,超過該角度,氣泡將直接位於邊界
private final int MAX_ANGLE = 30;
// 定義真機的Sensor管理器
private SensorManager mSensorManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 獲取水平儀的組件
view = (MyView) findViewById(R.id.main_myview);
// 獲取真機的傳感器管理服務
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
}

@Override
protected 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
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}

@Override
public void onSensorChanged(SensorEvent event) {
float[] values = event.values;
// 真機上獲取觸發的傳感器類型
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 = (view.back.getWidth() - view.bubble.getWidth()) / 2;
int y = (view.back.getHeight() - view.bubble.getHeight()) / 2;
// 如果與z軸的傾斜角還在最大角度之內
if (Math.abs(zAngle) <= MAX_ANGLE) {
// 根據與z軸的傾斜角計算x坐標的變化值(傾斜角度越大,x坐標變化越大)
int deltaX = (int) ((view.back.getWidth() - view.bubble
.getWidth()) / 2 * zAngle / MAX_ANGLE);
x += deltaX;
}
// 如果與z軸的傾斜角已經大於MAX_ANGLE,氣泡應到最左邊
else if (zAngle > MAX_ANGLE) {
x = 0;
}
// 如果與Z軸的傾斜角已經小於負的MAX_ANGLE,氣泡應到最右邊
else {
x = view.back.getWidth() - view.bubble.getWidth();
}
// 如果與Y軸的傾斜角還在最大角度之內
if (Math.abs(yAngle) <= MAX_ANGLE) {
// 根據與Y軸的傾斜角計算Y坐標的變化值(傾斜角度越大,Y坐標變化越大)
int deltaY = (int) ((view.back.getHeight() - view.bubble
.getHeight()) / 2 * zAngle / MAX_ANGLE);
y += deltaY;
}
// 如果與Y軸的傾斜角已經大於MAX_ANGLE,氣泡應到最下邊
else if (yAngle > MAX_ANGLE) {
y = view.back.getHeight() - view.bubble.getHeight();
}
// 如果與Y軸的傾斜角已經小於負的MAX_ANGLE,氣泡應到最右邊
else {
y = 0;
}
// 如果計算出來的X、Y坐標還位於水平儀的儀表盤內,更新水平儀的氣泡坐標
if (isContain(x, y)) {
view.bubbleX = x;
view.bubbleY = y;
}
// 通知系統重繪MyView組件
view.postInvalidate();
break;
}
}

// 計算X、Y點的氣泡是否處於水平儀的儀表盤內
private boolean isContain(int x, int y) {
// 計算氣泡的圓心坐標X、Y
int bubbleCx = x + view.bubble.getWidth() / 2;
int bubbleCy = y + view.bubble.getHeight() / 2;
// 計算水平儀儀表盤的圓心坐標X、Y
int backCx = view.back.getWidth() / 2;
int backCy = view.back.getHeight() / 2;
// 計算氣泡的圓心與水平儀儀表盤的圓心之間的距離
double distance = Math.sqrt((bubbleCx - backCx) * (bubbleCx - backCx)
+ (bubbleCy - backCy) * (bubbleCy - backCy));
// 若兩個圓心的距離小於它們的半徑差,即可認為處於該店的氣泡依然位於儀表盤內
if (distance < (view.back.getWidth() - view.bubble.getWidth()) / 2) {
return true;
} else {
return false;
}
}
}

 

自定義組件類(MyView):    
package com.home.view;  
  
import com.home.R;  
  
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 {  
    // 定義水平儀盤圖片   
    public Bitmap back;  
    // 定義水平儀中的氣泡圖標   
    public Bitmap bubble;  
    // 定義水平儀中氣泡的X、Y坐標   
    public 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);  
    }  
}  

package com.home.view;

import com.home.R;

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 {
// 定義水平儀盤圖片
public Bitmap back;
// 定義水平儀中的氣泡圖標
public Bitmap bubble;
// 定義水平儀中氣泡的X、Y坐標
public 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);
}
}

 

布局XML:  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent" >  
  
    <com.home.view.MyView  
        android:id="@+id/main_myview"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent" />  
  
</LinearLayout>  

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.home.view.MyView
        android:id="@+id/main_myview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

 


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved