感測器專題(2)-方向感測器


本節引言:

在上一節中我們中我們對感測器的一些基本概念進行了學習,以及學習了使用感測器的套路, 本節帶給大家的感測器是方向感測器的用法,好的,開始本節內容~


1.三維座標系的概念:

在Android平台中,感測器框架通常是使用一個標準的三維座標系來表示一個值的。以本節 要講的方向感測器為例子,要確定一個方向也需要一個三維座標,畢竟我們的裝置不可能永遠 都是水平端著的吧,安卓給我們回的方向值就是一個長度為3的flaot數組,包含三個方向 的值!官方API文件中有這樣一個圖:sensors_overview

1.png

#如果你看不懂圖,那就寫下文字解釋:

  • X軸的方向:沿著螢幕水平方向從左到右,如果手機如果不是正方形的話,較短的邊需要水平 放置,較長的邊需要垂直放置。
  • Y軸的方向:從螢幕的左下角開始沿著螢幕的垂直方向指向螢幕的頂端
  • Z軸的方向 :當水平放置時,指向天空的方向

2.方向感測器的三個值

上一節中說了,感測器的回調方法:onSensorChanged中的參數SensorEvent event,event的 值類型是Float[]的,而且最多只有三個元素,而方向感測器則剛好有三個元素,都表示度數! 對應的意義如下:

values[0]:方位角,手機繞著Z軸旋轉的角度。 0表示正北(North),90表示正東(East), 180表示正南(South),270表示正西(West)。假如values[0]的值剛好是這四個值的話, 而手機沿著水平放置的話,那麼當前手機的正前方就是這四個方向,可以利用這一點來 寫一個指南針!

values[1]:傾斜角,手機翹起來的程度,當手機繞著x軸傾斜時該值會改變。取值 範圍是[-180,180]之間。假如把手機放在桌面上,而桌面是完全水平的話,values1的則應該 是0,當然很少桌子是絕對水平的。從手機頂部開始抬起,直到手機沿著x軸旋轉180(此時螢幕 鄉下水平放在桌面上)。在這個旋轉過程中,values[1]的值會從0到-180之間變化,也就是手機抬起 時,values1的值會逐漸變小,知道等於-180;而加入從手機底部開始抬起,直到手機沿著x軸 旋轉180度,此時values[1]的值會從0到180之間變化。我們可以利用value[1]的這個特性結合 value[2]來實作一個平地尺!

value[2]:滾動角,沿著Y軸的滾動角度,取值範圍為:[-90,90],假設將手機螢幕朝上水平放在 桌面上,這時如果桌面是平的,values2的值應為0。將手機從左側逐漸抬起,values[2]的值將 逐漸減少,知道垂直於手機放置,此時values[2]的值為-90,從右側則是0-90;加入垂直位置 時繼續向右或向左滾動,values[2]的值將會繼續在-90到90之間變化!

假如你不是很懂,沒事我們寫個demo驗證下就知道了~


3.簡單的Demo幫助我們理解這三個值的變化:

運行效果圖

2.gif

實作程式碼

佈局程式碼:activity_main .xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp">

    <TextView
        android:id="@+id/tv_value1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="方位角"
        android:textSize="18sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/tv_value2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="倾斜角"
        android:textSize="18sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/tv_value3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="滚动角"
        android:textSize="18sp"
        android:textStyle="bold" /></LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private TextView tv_value1;
    private TextView tv_value2;
    private TextView tv_value3;
    private SensorManager sManager;
    private Sensor mSensorOrientation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mSensorOrientation = sManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
        sManager.registerListener(this, mSensorOrientation, SensorManager.SENSOR_DELAY_UI);
        bindViews();
    }

    private void bindViews() {
        tv_value1 = (TextView) findViewById(R.id.tv_value1);
        tv_value2 = (TextView) findViewById(R.id.tv_value2);
        tv_value3 = (TextView) findViewById(R.id.tv_value3);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        tv_value1.setText("方位角:" + (float) (Math.round(event.values[0] * 100)) / 100);
        tv_value2.setText("倾斜角:" + (float) (Math.round(event.values[1] * 100)) / 100);
        tv_value3.setText("滚动角:" + (float) (Math.round(event.values[2] * 100)) / 100);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }
}

程式碼非常簡單~,你想真正體驗下這三個值的變化,自己運行下程式轉轉手機就知道了~


4.一個簡易版的文字指南針範例

下面我們來寫個簡單的文字版的指南針來體驗體驗,當文字顯示正南的時候,表示手機 的正前方就是南方!

執行效果圖

3.gif

#程式碼實作

自訂View: CompassView.java

/**
 * Created by Jay on 2015/11/14 0014.
 */
public class CompassView extends View implements Runnable{

    private Paint mTextPaint;
    private int sWidth,sHeight;
    private float dec = 0.0f;
    private String msg  = "正北 0°";

    public CompassView(Context context) {
        this(context, null);
    }

    public CompassView(Context context, AttributeSet attrs) {
        super(context, attrs);
        sWidth = ScreenUtil.getScreenW(context);
        sHeight = ScreenUtil.getScreenH(context);
        init();
        new Thread(this).start();
    }



    public CompassView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {

        mTextPaint = new Paint();
        mTextPaint.setColor(Color.GRAY);
        mTextPaint.setTextSize(64);
        mTextPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText(msg, sWidth / 4 , sWidth / 2, mTextPaint);
    }

    // 更新指南针角度
    public void setDegree(float degree)
    {
        // 设置灵敏度
        if(Math.abs(dec - degree) >= 2 )
        {
            dec = degree;
            int range = 22;
            String degreeStr = String.valueOf(dec);

            // 指向正北
            if(dec > 360 - range && dec  90 - range && dec  180 - range && dec  270 - range && dec  45 - range && dec  135 - range && dec  225 - range && dec  315 - range && dec < 315 + range)
            {
                msg = "西北 " + degreeStr + "°";
            }
        }
    }


    @Override
    public void run() {
        while(!Thread.currentThread().isInterrupted())
        {
            try
            {
                Thread.sleep(100);
            }
            catch(InterruptedException e)
            {
                Thread.currentThread().interrupt();
            }
            postInvalidate();
        }
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private CompassView cView;
    private SensorManager sManager;
    private Sensor mSensorOrientation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        cView = new CompassView(MainActivity.this);
        sManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mSensorOrientation = sManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
        sManager.registerListener(this, mSensorOrientation, SensorManager.SENSOR_DELAY_UI);
        setContentView(cView);
    }


    @Override
    public void onSensorChanged(SensorEvent event) {
        cView.setDegree(event.values[0]);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        sManager.unregisterListener(this);
    }
}

這就是一個很簡單的指南針的雛形了,有興趣的可以自己繪製個羅盤和指針,然後實現一個 好看的指南針~


5.本節範例程式碼下載:

##SensorDemo2.zip

SensorDemo3.zip


4.jpg

########### ###本節小結:#########好的,本節為大家介紹了Android中最常用的方向感測器,以及他的簡單用法,以及 寫了一個指南針的例子,而完成指南針我們只用到一個values[0]的值,利用其他兩個 值我們也可以用來測量某地是否平躺,也就是製作水平尺,有空的可以寫個來玩~ 好的,就到這裡,謝謝~############