当前位置:网站首页>Andoird开发--指南针(基于手机传感器)
Andoird开发--指南针(基于手机传感器)
2022-07-31 08:36:00 【程@@程】
在Android中可以使用内置传感器(方向传感器、加速度传感器和地磁传感器等)实现指南针功能,编写出能够辨别手机方位的app。本文将讲述两种方法编写指南针app的方法,一是使用方向传感器,二是将加速度传感器和地磁传感器结合。
一、方向传感器
方向传感器是Android的基本传感器之一,通过三维坐标来确定(X,Y,Z)的三个方向,以进一步实现指南针功能,Sensor.TYPE_ORIENTATION在目前的Android系统中已经不再推荐使用,但是仍然可以通过其来获取数据。
实现代码(Activity):
//方向传感器指南针页面
public class CompassActivity1 extends AppCompatActivity implements SensorEventListener {
private ImageView iv_arrow;
private TextView tv_orientation;
private Context context;
private SensorManager sensorManager;//
private int currentSensorType;//方向角度
@Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout_compactivity);
iv_arrow = findViewById(R.id.iv_arrow);
tv_orientation = findViewById(R.id.tv_orientation);
context = CompassActivity1.this;
sensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
}
@Override
protected void onResume() {
super.onResume();
//为方向传感器注册监听器
List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
for (Sensor s : sensors) {
sensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_FASTEST);
}
}
@Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}
//1、北,2东北,3东,4东南,5南,6西南,7西,8西北
public void showLocationWithSensor(int type){
if(type==currentSensorType){
return;
}
currentSensorType = type;
Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.iv_arrow), dip2px(context,40), dip2px(context,40), true);
int degrees=0;//旋转角度
if(currentSensorType==1){
degrees=0;
tv_orientation.setText("北");
}else if(currentSensorType==2){
degrees=45;
tv_orientation.setText("东北");
}else if(currentSensorType==3){
degrees=90;
tv_orientation.setText("东");
}else if(currentSensorType==4){
degrees=135;
tv_orientation.setText("东南");
}else if(currentSensorType==5){
degrees=180;
tv_orientation.setText("南");
}else if(currentSensorType==6){
degrees=-135;
tv_orientation.setText("西南");
}else if(currentSensorType==7){
degrees=-90;
tv_orientation.setText("西");
}else if(currentSensorType==8){
degrees=-45;
tv_orientation.setText("西北");
}
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
Bitmap newBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
iv_arrow.setImageBitmap(newBmp);
}
@Override
public void onSensorChanged(SensorEvent event) {
if(event.sensor.getType()==Sensor.TYPE_ORIENTATION){
float degree = event.values[0]; //取围绕z轴转过的角度
float azimuth = (degree + 360) % 360;
if (azimuth <= 15 || azimuth >= 345) {
showLocationWithSensor(1);
} else if (15 < azimuth && azimuth < 75) {
showLocationWithSensor(2);
} else if (75 <= azimuth && azimuth <= 105) {
showLocationWithSensor(3);
} else if (105 < azimuth && azimuth < 165) {
showLocationWithSensor(4);
} else if (165 <= azimuth && azimuth <= 195) {
showLocationWithSensor(5);
} else if (195 < azimuth && azimuth < 255) {
showLocationWithSensor(6);
} else if (255 <= azimuth && azimuth <= 285) {
showLocationWithSensor(7);
} else if (285 < azimuth && azimuth < 345) {
showLocationWithSensor(8);
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
/** * dip转换px */
public static int dip2px(Context context, float dip) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dip * scale + 0.5f);
}
}
二、基于加速度传感器和地磁传感器
实现代码(Activity):
//基于加速度传感器和地磁传感器
public class CompassActivity2 extends AppCompatActivity implements SensorEventListener {
private ImageView iv_arrow;
private TextView tv_orientation;
private Context context;
private SensorManager sensorManager;//
private int currentSensorType;//方向角度
private float[] mGravity = new float[3];
private float[] mGeomagnetic = new float[3];
@Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout_compactivity);
iv_arrow = findViewById(R.id.iv_arrow);
tv_orientation = findViewById(R.id.tv_orientation);
context = CompassActivity2.this;
sensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
Sensor magneticSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); //加速度感应器
Sensor accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //地磁感应器
sensorManager.registerListener(this, magneticSensor, SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (sensorManager != null) {
sensorManager.unregisterListener(this);
}
}
//1、北,2东北,3东,4东南,5南,6西南,7西,8西北
public void showLocationWithSensor(int type){
if(type==currentSensorType){
return;
}
currentSensorType = type;
Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.iv_arrow), dip2px(context,40), dip2px(context,40), true);
int degrees=0;//旋转角度
if(currentSensorType==1){
degrees=0;
tv_orientation.setText("北");
}else if(currentSensorType==2){
degrees=45;
tv_orientation.setText("东北");
}else if(currentSensorType==3){
degrees=90;
tv_orientation.setText("东");
}else if(currentSensorType==4){
degrees=135;
tv_orientation.setText("东南");
}else if(currentSensorType==5){
degrees=180;
tv_orientation.setText("南");
}else if(currentSensorType==6){
degrees=-135;
tv_orientation.setText("西南");
}else if(currentSensorType==7){
degrees=-90;
tv_orientation.setText("西");
}else if(currentSensorType==8){
degrees=-45;
tv_orientation.setText("西北");
}
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
Bitmap newBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
iv_arrow.setImageBitmap(newBmp);
}
@Override
public void onSensorChanged(SensorEvent event) {
final float alpha = 0.97f;
synchronized (this) {
//指南针转动角度算法
//判断当前是加速度感应器还是地磁感应器
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity[0] = alpha * mGravity[0] + (1 - alpha) * event.values[0];
mGravity[1] = alpha * mGravity[1] + (1 - alpha) * event.values[1];
mGravity[2] = alpha * mGravity[2] + (1 - alpha) * event.values[2];
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
float[] values = event.values;
mGeomagnetic[0] = alpha * mGeomagnetic[0] + (1 - alpha) * event.values[0];
mGeomagnetic[1] = alpha * mGeomagnetic[1] + (1 - alpha) * event.values[1];
mGeomagnetic[2] = alpha * mGeomagnetic[2] + (1 - alpha) * event.values[2];
}
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
float azimuth = (float) Math.toDegrees(orientation[0]); // orientation
azimuth = (azimuth + 360) % 360;
if (azimuth <= 15 || azimuth >= 345) {
showLocationWithSensor(1);
} else if (15 < azimuth && azimuth < 75) {
showLocationWithSensor(2);
} else if (75 <= azimuth && azimuth <= 105) {
showLocationWithSensor(3);
} else if (105 < azimuth && azimuth < 165) {
showLocationWithSensor(4);
} else if (165 <= azimuth && azimuth <= 195) {
showLocationWithSensor(5);
} else if (195 < azimuth && azimuth < 255) {
showLocationWithSensor(6);
} else if (255 <= azimuth && azimuth <= 285) {
showLocationWithSensor(7);
} else if (285 < azimuth && azimuth < 345) {
showLocationWithSensor(8);
}
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
/** * dip转换px */
public static int dip2px(Context context, float dip) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dip * scale + 0.5f);
}
}
三、页面布局
这两个页面使用的同一个xml布局文件。
实现代码(xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout android:id="@+id/layout_arrow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:orientation="horizontal" android:gravity="center" android:layout_centerVertical="true">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="西" android:textStyle="bold" android:textSize="22sp" />
<ImageView android:id="@+id/iv_arrow" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginTop="10dp" android:src="@color/purple_500" android:layout_marginRight="10dp" android:layout_marginLeft="10dp"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="东" android:textStyle="bold" android:textSize="22sp"/>
</LinearLayout>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="南" android:textStyle="bold" android:textSize="22sp" android:layout_centerHorizontal="true" android:layout_below="@id/layout_arrow" android:layout_marginTop="10dp"/>
<TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="北" android:textStyle="bold" android:textSize="22sp" android:layout_above="@id/layout_arrow" android:layout_centerHorizontal="true"/>
<RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/layout_arrow" android:layout_marginTop="100dp">
<TextView android:id="@+id/tv_orientation" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="方位:东" android:textStyle="bold" android:textSize="22sp" android:layout_centerHorizontal="true"/>
</RelativeLayout>
</RelativeLayout>
总结
这两种方式都可以实现,不过方向传感器相对简单但是不提倡了。
指针实现用了Bitmap的偏移(旋转)操作。
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
Bitmap newBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
边栏推荐
- SSM框架讲解(史上最详细的文章)
- SQL连接表(内连接、左连接、右连接、交叉连接、全外连接)
- [MySQL exercises] Chapter 4 · Explore operators in MySQL with kiko
- 奉劝那些刚参加工作的学弟学妹们:要想进大厂,这些核心技能是你必须要掌握的!完整学习路线!
- 编译器R8问题Multidex
- 重装系统后,hosts文件配置后不生效
- 射频电路学习之滤波电路
- MySQL 排序
- (selenium)Service geckodriver unexpectedly exited. Status code was: 64
- 【idea 报错】 无效的目标发行版:17 的解决参考
猜你喜欢
【Unity】编辑器扩展-04-拓展Scene视图
2019 NeurIPS | Graph Convolutional Policy Network for Goal-Directed Molecular Graph Generation
功能强大的国产Api管理工具
[MySQL exercises] Chapter 2 Basic operations of databases and data tables
日志导致线程Block的这些坑,你不得不防
35-Jenkins-共享库应用
【小程序项目开发-- 京东商城】uni-app之自定义搜索组件(中)-- 搜索建议
力扣 593. 有效的正方形
MySQL安装常见报错处理大全
The torch distributed training
随机推荐
sqli-labs(less-11)
PowerCLi 通过自建PXE Server一键esxi7下批量部署常规New-VM
【C#】判断字符串中是否包含指定字符或字符串(Contains/IndexOf)
[What is the role of auto_increment in MySQL?】
我的创作纪念日
JSP config对象的简介说明
0730~Mysql优化
Vue项目通过node连接MySQL数据库并实现增删改查操作
一、MySQL主从复制原理
编译器R8问题Multidex
利用frp服务器进行内网穿透ssh访问
(selenium)Service geckodriver unexpectedly exited. Status code was: 64
期刊会议排名、信息检索网站推荐以及IEEE Latex模板下载
UML图及在drawio中的绘制
深度理解递归,手撕经典递归问题(汉诺塔,青蛙跳台阶),保姆级教学。
SSM integration case study (detailed)
二维坐标工具API
【小程序项目开发-- 京东商城】uni-app之自定义搜索组件(中)-- 搜索建议
[MySQL exercises] Chapter 5 · SQL single table query
Ubuntu安装Mysql5.7