方向传感器

Android 平台中,传感器框架通常是使用一个标准的三维坐标系来表示一个值的

要确定一个方向也需要一个三维坐标,毕竟我们的设备不可能永远都是水平端着的

Android 传感器返回的方向值就是一个长度为 3 的 flaot 数组,包含三个方向的值

方向 说明
X 轴的方向 沿着屏幕水平方向从左到右,如果手机如果不是是正方形的话
较短的边需要水平放置,较长的边需要垂直放置
Y 轴的方向 从屏幕的左下角开始沿着屏幕的的垂直方向指向屏幕的顶端
Z 轴的方向 当水平放置时,指向天空的方向

方向传感器的三个值

从上一章节中我们知道,传感器的回调方法:onSensorChanged() 中的参数 SensorEvent event,event 的值类型是 Float[] 的,而且最多只有三个元素,而方向传感器则刚好有三个元素,都表示度数

  1. values[0]

    方位角,手机绕着 Z 轴旋转的角度。0 表示正北 (North),90 表示正东 (East),180 表示正南(South),270 表示正西(West)

    假如 values[0] 的值刚好是这四个值的话,并且手机沿水平放置的话,那么当前手机的正前方就是这四个方向,可以利用这一点来写一个指南针!

  2. values[1]

    倾斜角,手机翘起来的程度,当手机绕着x轴倾斜时该值会发生变化,取值范围是 [-180,180] 之间

    1. 假如把手机放在桌面上,而桌面是完全水平的话,values[1] 的则应该是 0,当然很少桌子是绝对水平的

    2. 从手机 顶部开始抬起 ,直到手机沿着 x 轴旋转180(此时屏幕向下水平放在桌面上),在这个旋转过程中,values[1] 的值会从 0 到 -180 之间变化,即手机抬起时,values[1] 的值会逐渐变小,知道等于 -180;

    3. 从手机 底部开始抬起 ,直到手机沿着 x 轴旋转 180 度,此时 values[1] 的值会 从 0 到 180 之间变化

    我们可以利用 value[1] 的这个特性结合 value[2] 来实现一个平地尺!

  3. value[2]

    滚动角,沿着Y轴的滚动角度,取值范围为:[-90,90]

    1. 将手机屏幕朝上水平放在桌面上,这时如果桌面是平的,values[2] 的值应为 0
    2. 将手机从左侧逐渐抬起,values[2] 的值将逐渐减小,直到垂直于手机放置,此时 values[2]的值为 -90
    3. 从右侧则是 90
    4. 加入在垂直位置时继续向右或者向左滚动,values[2] 的值将会继续在 -90 到 90 之间变化

简单的 Demo

你可以拿着手机各种玩啥,看看三个值如何变换


  1. 创建一个 空的 Android 项目 cn.twle.android.OrientationSim

  2. 修改 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="16dp">
    
        <TextView
            android:id="@+id/ms_x"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="方位角"/>
    
        <TextView
            android:id="@+id/ms_y"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="倾斜角" />
    
        <TextView
            android:id="@+id/ms_z"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="滚动角" />
    
    </LinearLayout>
    
  3. 修改 MainActivity.java 文件

    package cn.twle.android.orientationsim;
    
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity implements SensorEventListener {
    
        private TextView ms_x,ms_y,ms_z;
        private SensorManager sm;
        private Sensor mSensorOrientation;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //获取传感器管理器
            sm = (SensorManager) getSystemService(SENSOR_SERVICE);
    
            // 获取方向传感器
            mSensorOrientation = sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);
    
            //注册数值变化监听器
            sm.registerListener(this, mSensorOrientation,SensorManager.SENSOR_DELAY_UI);
    
            ms_x = (TextView) findViewById(R.id.ms_x);
            ms_y = (TextView) findViewById(R.id.ms_y);
            ms_z = (TextView) findViewById(R.id.ms_z);
        }
    
        // 传感器数值变化会调用此方法
    
        @Override
        public void onSensorChanged(SensorEvent event) {
    
            ms_x.setText("方位角:" + (float) (Math.round(event.values[0] * 100)) / 100);
            ms_y.setText("倾斜角:" + (float) (Math.round(event.values[1] * 100)) / 100);
            ms_z.setText("滚动角:" + (float) (Math.round(event.values[2] * 100)) / 100);
        }
    
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
    
        }
    }
    

文字指南针

接下来我们写一个简单的文字版的指南针来体验方向传感器,当文字显示正南的时候,表示手机的正前方就是南方


文字版的超级没方向感,我都怀疑自己的认知了

  1. 创建一个 空的 Android 项目 cn.twle.android.Compass

  2. 这次我们尝试抛弃 activity_main.xml,使用纯代码布局

    自定义一个 View 文件名 MsCompassView.java

    应该知道文件放哪里吧,作为教学,我一向怎么简单怎么来

    package cn.twle.android.compass;
    
    import android.content.Context;
    import android.content.res.Resources;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.util.AttributeSet;
    import android.util.DisplayMetrics;
    import android.view.View;
    
    public class MsCompassView extends View implements Runnable{
    
        private Paint mTextPaint;
        private int msWidth,msHeight;
        private float dec = 0.0f;
        private String msg  = "正北 0°";
    
        public MsCompassView(Context context) {
            this(context, null);
        }
    
        public MsCompassView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            // 获取屏幕高宽
    
            Resources resources = this.getResources();
            DisplayMetrics dm = resources.getDisplayMetrics();
    
            msWidth = dm.widthPixels;
            msHeight = dm.heightPixels;
    
            // 初始化画笔
    
            mTextPaint = new Paint();
            mTextPaint.setColor(Color.GRAY);
            mTextPaint.setTextSize(64);
            mTextPaint.setStyle(Paint.Style.FILL);
    
            new Thread(this).start();
        }
    
        public MsCompassView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawText(msg, msWidth / 4 , msWidth / 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 < 360 + range)
                {
                    msg = "正北 " + degreeStr + "°";
                }
    
                // 指向正东
                if(dec > 90 - range && dec < 90 + range)
                {
                    msg = "正东 " + degreeStr + "°";
                }
    
                // 指向正南
                if(dec > 180 - range && dec < 180 + range)
                {
                    msg = "正南 " + degreeStr + "°";
                }
    
                // 指向正西
                if(dec > 270 - range && dec < 270 + range)
                {
                    msg = "正西 " + degreeStr + "°";
                }
    
                // 指向东北
                if(dec > 45 - range && dec < 45 + range)
                {
                    msg = "东北 " + degreeStr + "°";
                }
    
                // 指向东南
                if(dec > 135 - range && dec < 135 + range)
                {
                    msg = "东南 " + degreeStr + "°";
                }
    
                // 指向西南
                if(dec > 225 - range && dec < 225 + range)
                {
                    msg = "西南 " + degreeStr + "°";
                }
    
                // 指向西北
                if(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();
            }
        }
    }
    
  3. 修改文件 MainActivity.java 加载我们自定义的 MsCompassView

    package cn.twle.android.compass;
    
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    public class MainActivity extends AppCompatActivity implements SensorEventListener {
    
        private MsCompassView ms_cview;
        private SensorManager sm;
        private Sensor mSensorOrientation;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ms_cview = new MsCompassView(MainActivity.this);
    
            sm = (SensorManager) getSystemService(SENSOR_SERVICE);
            mSensorOrientation = sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);
    
            sm.registerListener(this, mSensorOrientation, SensorManager.SENSOR_DELAY_UI);
            setContentView(ms_cview);
        }
    
        @Override
        public void onSensorChanged(SensorEvent event) {
            ms_cview.setDegree(event.values[0]);
        }
    
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            sm.unregisterListener(this);
        }
    }
    

参考文档

  1. 官方 API 文档: 传感器

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.