センサーのトピック (2)——方向センサー


このセクションの紹介:

前のセクションでは、センサーの基本概念をいくつか学習し、センサーを使用する手順を学習しました。 このセクションで説明するセンサーは、方向センサーの使用法です。それでは、このセクションを始めましょう~


1. 3 次元座標系の概念:

Android プラットフォームでは、センサー フレームは通常、値を表す標準の 3 次元座標系。このセクションをご覧ください 方向センサーを例に挙げてみましょう。結局のところ、私たちの機器は永久に使用できるわけではありません。 これらはすべて水平に保持されます。Android から返される方向の値は、3 つの方向を含む長さ 3 のフラット配列です。 価値!公式 API ドキュメントにはそのような図があります: sensors_overview

1.png

画像が理解できない場合は、テキストの説明を書き留めてください:

  • X 軸の方向:左から画面の水平方向に沿って右、携帯電話が正方形でない場合は、短い辺が水平である必要があります 置き場所は長辺を垂直に置く必要があります。
  • Y軸方向: 画面の左下隅から始まり、画面の垂直方向に沿って画面の上を指す方向
  • Z軸方向: 横置きの場合、その方向を指す空の 3 つの値

2. 方向センサーの 3 つの値

前のセクションで説明したように、センサーのコールバック メソッド: onSensorChanged の SensorEvent イベント、event 値のタイプは Float[] で、要素は最大 3 つありますが、方向センサーにはちょうど 3 つの要素があり、すべて度を表します。 対応する意味は次のとおりです:

values[0]: 方位角、携帯電話が Z 軸の周りを回転する角度。 0 は北を意味し、90 は東を意味します。 180 は真南 (South)、270 は真西 (West) を意味します。 value[0] の値がたまたまこれら 4 つの値であった場合、 そして、携帯電話を水平に置いた場合、現在の携帯電話の正面はこの 4 方向になります。 コンパスを書いてみよう!

values[1]: 傾斜角度、携帯電話が傾く度合い。この値は、携帯電話が x 軸の周りに傾くと変化します。価値 範囲は[-180,180]です。携帯電話がデスクトップ上に置かれ、デスクトップが完全に水平である場合、値1は次のようになります。 もちろん、完全に水平なテーブルはほとんどありません。携帯電話 の上部から携帯電話 を持ち上げ始め、携帯電話が X 軸に沿って 180 度回転します (この時点で画面 田舎はテーブルの上に水平に置かれます)。この回転プロセス中に、values[1] の値は 0 から -180 に変化します。つまり、電話が持ち上げられます。 の場合、値 1 は -180 になるまで徐々に小さくなり、携帯電話 の底部から携帯電話が x 軸に沿って移動するまで を持ち上げ始めます。 180度回転すると、values[1]の値が0から180まで変化します。 value[1]のこの特徴を使用して組み合わせることができます value[2]で平らな定規を実装します!

value[2]: スクロール角度、Y 軸に沿ったスクロール角度、値の範囲は [-90,90]、携帯電話の画面が水平上向きに配置されていると仮定します。 デスクトップ上では、この時デスクトップが平らであればvalues2の値は0になるはずです。携帯電話を左側から徐々に持ち上げると、values[2]の値が 携帯電話に対して垂直に配置されるまで徐々に減少します。このとき、values[2]の値は右から0〜90です。 右または左にスクロールし続けると、values[2]の値が-90から90の間で変化し続けます。

よく理解できなくても大丈夫です。デモを書いて確認してみましょう~


3. 簡単なデモは、次の 3 つの値の変化を理解するのに役立ちます:

レンダリングの実行:

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) {

    }
}
コードは非常に簡単です~、これら3つの値の変化を実際に体験したい場合は、プログラムを自分で実行してください。携帯電話に転送するだけでわかります〜

4. 簡単なテキストコンパスの例

テキストが真南を示したら、コンパスの簡単なテキストバージョンを書いてみましょう。それは携帯電話を意味します すぐ目の前は南です!

レンダリングの実行

:

3.gif

コード実装

:Custom 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


このセクションの概要:

このセクションでは、最も一般的に使用される方向センサーを紹介します。 Android とその簡単な使用法、および コンパスの例を書きました。コンパスを完成させるには、値 [0] を 1 つだけ使用し、残りの 2 つを使用します。 また、特定の場所が平らになっているかどうかを測定する、つまり水平定規を作成するためにも使用できます。時間があれば、書いて楽しむこともできます。 わかりました、ありがとうございます~4.jpg