自定义View实践:指南针的实现

本文详细讲解了如何使用自定义View在Android中实现指南针效果,包括通过SensorManager结合磁力计和加速度计计算方向,以及如何在自定义View中绘制指南针。
摘要由CSDN通过智能技术生成

自定义View实践:指南针的实现

本文将介绍如何通过自定义View实现了一个指南针的效果,效果图如下:
指南针效果

源码GitHub地址

首先是根据磁力计和加速度计计算南向和手机的夹角。通过Android的SensorManager类进行计算,使用的是右手坐标系:
右手坐标系

获取SensorManager,并初始化磁力计和加速度计:

public class CompassActivity extends AppCompatActivity implements SensorEventListener {
       
    private SensorManager mSensorManager;    
    private Sensor mMagneticSensor;    
    private Sensor mAccelerateSensor;

    @Overrideprotected void onCreate(Bundle savedInstanceState) {
          
        ...
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);    
        if (mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null && mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) 
        {
           
            mMagneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);        
            mAccelerateSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);        
            mHasNeededSensors = true;    
        } else {
       
            Toast.makeText(this, "没有磁力计或加速度计", Toast.LENGTH_SHORT).show();    
            return;
        }
}

在onResume里面注册磁力计和加速度计,并在onPause的时候解除注册:

@Override
protected void onResume() {
       
    super.onResume();    
    if (mHasNeededSensors) {
           
        mSensorManager.registerListener(this, mMagneticSensor, SensorManager.SENSOR_DELAY_NORMAL);        
        mSensorManager.registerListener(this, mAccelerateSensor, SensorManager.SENSOR_DELAY_NORMAL);    
    }
}

@Override
protected void onPause() {
       
    super.onPause();    
    if (mHasNeededSensors) {
           
        mSensorManager.unregisterListener(this);    
    }
}

实现onSensorChanged接口,这样当磁力计或加速度计数值发生变化的时候会调用该函数告知新数值:

@Override
public void onSensorChanged(SensorEvent event) {
      
    if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
           
        mMagneticFieldValues = event.values;    
    } else if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
           
        mAccelerometerValues = event.values;    
    }    
    calculateOrientation();
}

通过calculateOrientation函数计算南向跟手机x轴的夹角,这里用到SensorManager的两个函数,getRotationMatrix和getOrientation。具体计算原理可以参阅两个函数的实现,用法很简单,传入加速度计和磁力计数值即可。得到一个3X1的矩阵,矩阵的三个值代表南向绕三个坐标轴旋转的角度,单位是弧度,我们绘制指南针只需要使用矩阵的第一个值,即南向绕Z轴顺时针旋转过的角度,用alpha表示。当南向指向手机正上方时,alpha=0;指向手机正下方时,alpha=MATH.PI,如下图所示:
南向和手机Y轴的夹角

为了方便使用极坐标绘制指南针的罗盘,我们把它转换成和X轴的夹角seta,seta=alpha-Math.PI/2,计算的代码如下:

// 计算指南针的南向和手机x轴的角度,以弧度表示(-PI, PI]
private void calculateOrientation() {
       
    float[] results = new float[3];    
    float[] rotates = new float[9];    

    SensorManager.getRotationMatrix(rotates, null, mAccelerometerValues, mMagneticFieldValues);    
    SensorManager.getOrientation(rotates, results);    
    // alpha是南向和手机Y轴的夹角    
    float alpha = results[0];    
    float seta;    
    // 将alpha转换成南向和手机X轴的夹角,便于使用极坐标系绘制指南针的圆盘    
    if ((alpha - (-Math.PI)) < 0.000000001) {
           
        seta = (float) (Math.PI / 2);    
    } else {
           
        seta = (float) (alpha - Math.PI / 2);    
    }    

    Log.i("compass:", Math.toDegrees(seta)+"");    
    mCompassView.setSouth(seta);    
    mCompassView.invalidate();
}

利用夹角seta,我们就可以利用自定义View绘制指南针了。
首先定义指南针View的属性,通过这些属性,我们可以控制指南针的外观:

<resources>    
    <declare-styleable name="CompassViewStyle">        
        <attr name="radius" format="dimension" /> <!--罗盘半径-->
        <attr name="short_dash" format="dimension" /> <!--罗盘外圈短辐射线的长度-->
        <attr name="long_dash" format="dimension" />  <!--罗盘外圈长辐射线的长度-->
        <attr name="text_size" format="dimension" />  <!--罗盘上文字的尺寸-->    
    </declare-styleable
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值