Android指南针应用编写
2023-09-11 14:19:59 时间
目录
概述
由于最近有个地磁项目的需要,重温多年Android知识,通过手机地磁传感器数据,编写了一个指南针App,同时支持,获取手机端各个传感器数据,如:陀螺仪、地磁、加速度、方位/向传感器。
一、运行环境:
1、vivo手机 MIUI版本 12.5.4
2、Android Studio Arctic Fox | 2020.3.1
二、编码
1、创建MiCompass.java文件(自定义view)
package com.example.mycompass;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.Matrix;
import android.graphics.Camera;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Color;
import android.graphics.RadialGradient;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
public class MiCompass extends View{
private Canvas mCanvas;
private Context mContext;
//View矩形的宽度
private int width;
//指南针圆心点坐标
private int mCenterX;
private int mCenterY;
//外圆半径
private int mOutSideRadius;
//外接圆半径
private int mCircumRadius;
//指南针文字大小空间高度
private int mTextHeight;
//暗红色 外圈笔
private Paint mDarkRedPaint;
//深灰 外圈笔
private Paint mDeepGrayPaint;
//外三角笔
private Paint mOutSideCircumPaint;
//浅灰 外圈笔
private Paint mLightGrayPaint;
//指南针上面 文字笔
private Paint mTextPaint;
//外接圆,三角形笔
private Paint mCircumPaint;
//指南针上面文字的外接矩形,用来测文字大小让文字居中
private Rect mTextRect;
//外圈小三角形的Path
private Path mOutsideTriangle;
//外接圆小三角形的Path
private Path mCircumTriangle;
//NESW 文字笔 和文字外接矩形
private Paint mNorthPaint;
private Paint mOthersPaint;
private Rect mPositionRect;
//小刻度文字大小矩形和画笔
private Paint mSamllDegreePaint;
//两位数的
private Rect mSencondRect;
//三位数的
private Rect mThirdRect;
//圆心数字矩形
private Rect mCenterTextRect;
//中心文字笔
private Paint mCenterPaint;
//内心圆是一个颜色辐射渐变的圆
private Shader mInnerShader;
private Paint mInnerPaint;
//定义个点击属性动画
private ValueAnimator mValueAnimator;
// camera绕X轴旋转的角度
private float mCameraRotateX;
// camera绕Y轴旋转的角度
private float mCameraRotateY;
//camera最大旋转角度
private float mMaxCameraRotate = 10;
// camera绕X轴旋转的角度
private float mCameraTranslateX;
// camera绕Y轴旋转的角度
private float mCameraTranslateY;
//camera最大旋转角度
private float mMaxCameraTranslate;
//camera矩阵
private Matrix mCameraMatrix;
//设置camera
private Camera mCamera;
private float val=0f;
private float valCompare;
//偏转角度红线笔
private Paint mAnglePaint;
//方位文字
private String text="北";
public float getVal() {
return val;
}
public void setVal(float val) {
this.val = val;
invalidate();
}
public MiCompass(Context context) {
this(context,null);
}
public MiCompass(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public MiCompass(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
mDarkRedPaint = new Paint();
mDarkRedPaint.setStyle(Paint.Style.STROKE);
mDarkRedPaint.setAntiAlias(true);
mDarkRedPaint.setColor(context.getResources().getColor(R.color.darkRed));
mDeepGrayPaint = new Paint();
mDeepGrayPaint.setStyle(Paint.Style.STROKE);
mDeepGrayPaint.setAntiAlias(true);
mDeepGrayPaint.setColor(context.getResources().getColor(R.color.deepGray));
mLightGrayPaint = new Paint();
mLightGrayPaint.setStyle(Paint.Style.FILL);
mLightGrayPaint.setAntiAlias(true);
mLightGrayPaint.setColor(context.getResources().getColor(R.color.lightGray));
mTextPaint = new Paint();
mTextPaint.setStyle(Paint.Style.STROKE);
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(80);
mTextPaint.setColor(context.getResources().getColor(R.color.white));
mCircumPaint = new Paint();
mCircumPaint.setStyle(Paint.Style.FILL);
mCircumPaint.setAntiAlias(true);
mCircumPaint.setColor(context.getResources().getColor(R.color.red));
mOutSideCircumPaint = new Paint();
mOutSideCircumPaint.setStyle(Paint.Style.FILL);
mOutSideCircumPaint.setAntiAlias(true);
mOutSideCircumPaint.setColor(context.getResources().getColor(R.color.lightGray));
mTextRect = new Rect();
mOutsideTriangle = new Path();
mCircumTriangle = new Path();
mNorthPaint = new Paint();
mNorthPaint.setStyle(Paint.Style.STROKE);
mNorthPaint.setAntiAlias(true);
mNorthPaint.setTextSize(40);
mNorthPaint.setColor(context.getResources().getColor(R.color.red));
mOthersPaint = new Paint();
mOthersPaint.setStyle(Paint.Style.STROKE);
mOthersPaint.setAntiAlias(true);
mOthersPaint.setTextSize(40);
mOthersPaint.setColor(context.getResources().getColor(R.color.white));
mPositionRect = new Rect();
mCenterTextRect = new Rect();
mCenterPaint = new Paint();
mCenterPaint.setStyle(Paint.Style.STROKE);
mCenterPaint.setAntiAlias(true);
mCenterPaint.setTextSize(120);
mCenterPaint.setColor(context.getResources().getColor(R.color.white));
mSamllDegreePaint = new Paint();
mSamllDegreePaint.setStyle(Paint.Style.STROKE);
mSamllDegreePaint.setAntiAlias(true);
mSamllDegreePaint.setTextSize(30);
mSamllDegreePaint.setColor(context.getResources().getColor(R.color.lightGray));
mSencondRect = new Rect();
mThirdRect = new Rect();
mInnerPaint = new Paint();
mInnerPaint.setStyle(Paint.Style.FILL);
mInnerPaint.setAntiAlias(true);
mAnglePaint = new Paint();
mAnglePaint.setStyle(Paint.Style.STROKE);
mAnglePaint.setAntiAlias(true);
mAnglePaint.setColor(context.getResources().getColor(R.color.red));
mCameraMatrix = new Matrix();
mCamera = new Camera();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mCanvas = canvas;
//设置Camera矩阵 实现3D效果
set3DMetrix();
//画文字
drawText();
//画指南针外圈
drawCompassOutSide();
//画指南针外接圆
drawCompassCircum();
//画内部渐变颜色圆
drawInnerCricle();
//画指南针内部刻度
drawCompassDegreeScale();
//画圆心数字
drawCenterText();
}
/**
* 设置camera相关
*/
private void set3DMetrix() {
mCameraMatrix.reset();
mCamera.save();
mCamera.rotateX(mCameraRotateX);
mCamera.rotateY(mCameraRotateY);
mCamera.getMatrix(mCameraMatrix);
mCamera.restore();
//camera默认旋转是View左上角为旋转中心
//所以动作之前要,设置矩阵位置 -mTextHeight-mOutSideRadius
mCameraMatrix.preTranslate(-getWidth()/2,-getHeight()/2);
//动作之后恢复位置
mCameraMatrix.postTranslate(getWidth()/2,getHeight()/2);
mCanvas.concat(mCameraMatrix);
}
private void drawInnerCricle() {
mInnerShader = new RadialGradient(width/2,mOutSideRadius+mTextHeight,mCircumRadius-40, Color.parseColor("#323232"),
Color.parseColor("#000000"),Shader.TileMode.CLAMP);
mInnerPaint.setShader(mInnerShader);
mCanvas.drawCircle(width/2,mOutSideRadius+mTextHeight,mCircumRadius-40,mInnerPaint);
}
private void drawCenterText() {
String centerText=String.valueOf((int) val+"°");
mCenterPaint.getTextBounds(centerText,0,centerText.length(),mCenterTextRect);
int centerTextWidth = mCenterTextRect.width();
int centerTextHeight = mCenterTextRect.height();
mCanvas.drawText(centerText,width/2-centerTextWidth/2,mTextHeight+mOutSideRadius+centerTextHeight/5,mCenterPaint);
}
private void drawCompassDegreeScale() {
mCanvas.save();
//获取N文字的宽度
mNorthPaint.getTextBounds("N",0,1,mPositionRect);
int mPositionTextWidth = mPositionRect.width();
int mPositionTextHeight = mPositionRect.height();
//获取W文字宽度,因为W比较宽 所以要单独获取
mNorthPaint.getTextBounds("W",0,1,mPositionRect);
int mWPositionTextWidth = mPositionRect.width();
int mWPositionTextHeight = mPositionRect.height();
//获取小刻度,两位数的宽度
mSamllDegreePaint.getTextBounds("30",0,1,mSencondRect);
int mSencondTextWidth = mSencondRect.width();
int mSencondTextHeight = mSencondRect.height();
//获取小刻度,3位数的宽度
mSamllDegreePaint.getTextBounds("30",0,1,mThirdRect);
int mThirdTextWidth = mThirdRect.width();
int mThirdTextHeight = mThirdRect.height();
mCanvas.rotate(-val,width/2,mOutSideRadius+mTextHeight);
//画刻度线
for (int i = 0; i < 240; i++) {
if (i==0||i==60||i==120||i==180){
mCanvas.drawLine(getWidth() / 2, mTextHeight+mOutSideRadius-mCircumRadius+10,
getWidth() / 2, mTextHeight+mOutSideRadius-mCircumRadius+30, mDeepGrayPaint);
}else{
mCanvas.drawLine(getWidth() / 2, mTextHeight+mOutSideRadius-mCircumRadius+10,
getWidth() / 2, mTextHeight+mOutSideRadius-mCircumRadius+30, mLightGrayPaint);
}
if (i==0){
mCanvas.drawText("N", this.width /2-mPositionTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mPositionTextHeight,mNorthPaint);
}else if (i==60){
mCanvas.drawText("E", this.width /2-mPositionTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mPositionTextHeight,mOthersPaint);
}else if (i==120){
mCanvas.drawText("S", this.width /2-mPositionTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mPositionTextHeight,mOthersPaint);
}else if (i==180){
mCanvas.drawText("W", this.width /2-mWPositionTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mWPositionTextHeight,mOthersPaint);
}else if (i==20){
mCanvas.drawText("30", this.width /2-mSencondTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mSencondTextHeight,mSamllDegreePaint);
}else if (i==40){
mCanvas.drawText("60", this.width /2-mSencondTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mSencondTextHeight,mSamllDegreePaint);
}else if (i==80){
mCanvas.drawText("120", this.width /2-mThirdTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mThirdTextHeight,mSamllDegreePaint);
}else if (i==100){
mCanvas.drawText("150", this.width /2-mThirdTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mThirdTextHeight,mSamllDegreePaint);
}else if (i==140){
mCanvas.drawText("210", this.width /2-mThirdTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mThirdTextHeight,mSamllDegreePaint);
}else if (i==160){
mCanvas.drawText("240", this.width /2-mThirdTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mThirdTextHeight,mSamllDegreePaint);
}else if (i==200){
mCanvas.drawText("300", this.width /2-mThirdTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mThirdTextHeight,mSamllDegreePaint);
}else if (i==220){
mCanvas.drawText("330", this.width /2-mThirdTextWidth/2,mTextHeight+mOutSideRadius-mCircumRadius+40+mThirdTextHeight,mSamllDegreePaint);
}
mCanvas.rotate(1.5f, mCenterX, mOutSideRadius+mTextHeight);
}
mCanvas.restore();
}
/**
* 指南针外接圆,和外部圆换道理差不多
*/
private void drawCompassCircum() {
mCanvas.save();
//外接圆小三角形的高度
int mTriangleHeight=(mOutSideRadius-mCircumRadius)/2;
mCanvas.rotate(-val,width/2,mOutSideRadius+mTextHeight);
mCircumTriangle.moveTo(width/2,mTriangleHeight+mTextHeight);
//内接三角形的边长,简单数学运算
float mTriangleSide = (float) ((mTriangleHeight/(Math.sqrt(3)))*2);
mCircumTriangle.lineTo(width/2-mTriangleSide/2,mTextHeight+mTriangleHeight*2);
mCircumTriangle.lineTo(width/2+mTriangleSide/2,mTextHeight+mTriangleHeight*2);
mCircumTriangle.close();
mCanvas.drawPath(mCircumTriangle,mCircumPaint);
mCanvas.drawArc(width/2-mCircumRadius,mTextHeight+mOutSideRadius-mCircumRadius,
width/2+mCircumRadius,mTextHeight+mOutSideRadius+mCircumRadius,-85,350,false,mDeepGrayPaint);
mAnglePaint.setStrokeWidth(5f);
if (val<=180){
valCompare = val;
mCanvas.drawArc(width/2-mCircumRadius,mTextHeight+mOutSideRadius-mCircumRadius,
width/2+mCircumRadius,mTextHeight+mOutSideRadius+mCircumRadius,-85,valCompare,false,mAnglePaint);
}else{
valCompare = 360-val;
mCanvas.drawArc(width/2-mCircumRadius,mTextHeight+mOutSideRadius-mCircumRadius,
width/2+mCircumRadius,mTextHeight+mOutSideRadius+mCircumRadius,-95,-valCompare,false,mAnglePaint);
}
mCanvas.restore();
}
/**
* 指南针外部可简单分为两部分
* 1、用Path实现小三角形
* 2、两个圆弧
*/
private void drawCompassOutSide() {
mCanvas.save();
//小三角形的高度
int mTriangleHeight=40;
//定义Path画小三角形
mOutsideTriangle.moveTo(width/2,mTextHeight-mTriangleHeight);
//小三角形的边长
float mTriangleSide = 46.18f;
//画出小三角形
mOutsideTriangle.lineTo(width/2-mTriangleSide/2,mTextHeight);
mOutsideTriangle.lineTo(width/2+mTriangleSide/2,mTextHeight);
mOutsideTriangle.close();
mCanvas.drawPath(mOutsideTriangle,mOutSideCircumPaint);
//画圆弧
mDarkRedPaint.setStrokeWidth((float) 5);
mLightGrayPaint.setStrokeWidth((float)5);
mDeepGrayPaint.setStrokeWidth((float)3);
mLightGrayPaint.setStyle(Paint.Style.STROKE);
mCanvas.drawArc(width/2-mOutSideRadius,mTextHeight,width/2+mOutSideRadius,mTextHeight+mOutSideRadius*2,-80,120,false,mLightGrayPaint);
mCanvas.drawArc(width/2-mOutSideRadius,mTextHeight,width/2+mOutSideRadius,mTextHeight+mOutSideRadius*2,40,20,false,mDeepGrayPaint);
mCanvas.drawArc(width/2-mOutSideRadius,mTextHeight,width/2+mOutSideRadius,mTextHeight+mOutSideRadius*2,-100,-20,false,mLightGrayPaint);
mCanvas.drawArc(width/2-mOutSideRadius,mTextHeight,width/2+mOutSideRadius,mTextHeight+mOutSideRadius*2,-120,-120,false,mDarkRedPaint);
mCanvas.restore();
}
private void drawText() {
if (val<=15||val>=345){
text = "北";
}else if (val>15&&val<=75){
text= "东北";
}else if (val>75&&val<=105){
text= "东";
}else if (val>105&&val<=165){
text="东南";
}else if (val>165&&val<=195){
text = "南";
}else if (val>195&&val<=255){
text = "西南";
}else if (val>255&&val<=285){
text = "西";
}else if (val>285&&val<345){
text="西北";
}
mTextPaint.getTextBounds(text,0,text.length(),mTextRect);
//文字宽度
int mTextWidth = mTextRect.width();
//让文字水平居中显示
mCanvas.drawText(text,width/2-mTextWidth/2,mTextHeight/2,mTextPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
width = Math.min(widthSize, heightSize);
if (widthMode == MeasureSpec.UNSPECIFIED) {
width = heightSize;
} else if (heightMode == MeasureSpec.UNSPECIFIED) {
width = widthSize;
}
//为指南针上面的文字预留空间,定为1/3边张
mTextHeight = width/3;
//设置圆心点坐标
mCenterX = width/2;
mCenterY = width/2+mTextHeight;
//外部圆的外径
mOutSideRadius = width*3/8;
//外接圆的半径
mCircumRadius = mOutSideRadius*4/5;
//camera最大平移距离
mMaxCameraTranslate = 0.02f*mOutSideRadius;
setMeasuredDimension(width, width+width/3 );
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if (mValueAnimator!=null&&mValueAnimator.isRunning()){
mValueAnimator.cancel();
}
//3D 效果让Camera旋转,获取旋转偏移大小
getCameraRotate(event);
//获取平移大小
getCameraTranslate(event);
break;
case MotionEvent.ACTION_MOVE:
//3D 效果让Camera旋转,获取旋转偏移大小
getCameraRotate(event);
//获取平移大小
getCameraTranslate(event);
break;
case MotionEvent.ACTION_UP:
//松开手 复原动画
startRestore();
break;
}
return true;
}
private void startRestore() {
final String cameraRotateXName = "cameraRotateX";
final String cameraRotateYName = "cameraRotateY";
final String canvasTranslateXName = "canvasTranslateX";
final String canvasTranslateYName = "canvasTranslateY";
PropertyValuesHolder cameraRotateXHolder =
PropertyValuesHolder.ofFloat(cameraRotateXName, mCameraRotateX, 0);
PropertyValuesHolder cameraRotateYHolder =
PropertyValuesHolder.ofFloat(cameraRotateYName, mCameraRotateY, 0);
PropertyValuesHolder canvasTranslateXHolder =
PropertyValuesHolder.ofFloat(canvasTranslateXName, mCameraTranslateX, 0);
PropertyValuesHolder canvasTranslateYHolder =
PropertyValuesHolder.ofFloat(canvasTranslateYName, mCameraTranslateY, 0);
mValueAnimator = ValueAnimator.ofPropertyValuesHolder(cameraRotateXHolder,
cameraRotateYHolder, canvasTranslateXHolder, canvasTranslateYHolder);
mValueAnimator.setInterpolator(new TimeInterpolator() {
@Override
public float getInterpolation(float input) {
float f = 0.571429f;
return (float) (Math.pow(2, -2 * input) * Math.sin((input - f / 4) * (2 * Math.PI) / f) + 1);
}
});
mValueAnimator.setDuration(1000);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCameraRotateX = (float) animation.getAnimatedValue(cameraRotateXName);
mCameraRotateY = (float) animation.getAnimatedValue(cameraRotateYName);
mCameraTranslateX = (float) animation.getAnimatedValue(canvasTranslateXName);
mCameraTranslateX = (float) animation.getAnimatedValue(canvasTranslateYName);
}
});
mValueAnimator.start();
}
/**
* 获取Camera,平移大小
* @param event
*/
private void getCameraTranslate(MotionEvent event) {
float translateX = (event.getX() - getWidth() / 2);
float translateY = (event.getY() - getHeight()/2);
//求出此时位移的大小与半径之比
float[] percentArr = getPercent(translateX, translateY);
//最终位移的大小按比例匀称改变
mCameraTranslateX = percentArr[0] * mMaxCameraTranslate;
mCameraTranslateY = percentArr[1] * mMaxCameraTranslate;
}
/**
* 让Camera旋转,获取旋转偏移大小
* @param event
*/
private void getCameraRotate(MotionEvent event) {
float mRotateX = -(event.getY()-(getHeight())/2);
float mRotateY = (event.getX()-getWidth()/2);
//求出旋转大小与半径之比
float[] percentArr = getPercent(mRotateX,mRotateY);
mCameraRotateX = percentArr[0]*mMaxCameraRotate;
mCameraRotateY = percentArr[1]*mMaxCameraRotate;
}
/**
* 获取比例
* @param mCameraRotateX
* @param mCameraRotateY
* @return
*/
private float[] getPercent(float mCameraRotateX, float mCameraRotateY) {
float[] percentArr = new float[2];
float percentX = mCameraRotateX/width;
float percentY = mCameraRotateY/width;
//处理一下比例值
if (percentX > 1) {
percentX = 1;
} else if (percentX < -1) {
percentX = -1;
}
if (percentY > 1) {
percentY = 1;
} else if (percentY < -1) {
percentY = -1;
}
percentArr[0] = percentX;
percentArr[1] = percentY;
return percentArr;
}
}
2、colors.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="black">#000</color>
<color name="darkRed">#702216</color>
<color name="lightGray">#323232</color>
<color name="deepGray">#8B8B8B</color>
<color name="white">#fff</color>
<color name="red">#f00</color>
<color name="ocbg">#237EAD</color>
</resources>
3、value\themes.xml、value-nigth\themes.xml文件
此时有两个报错,不用怕,挨个解决,挨个创建即可。
报错的地方,按照以上方法,挨个创建即可,创建好之后如下所示:
4、activity_main.xml文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/accSensor_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="加速度传感器"/>
<TextView
android:id="@+id/mangeticSensor_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="地磁传感器"/>
<TextView
android:id="@+id/gyroscopeSensor_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="陀螺仪感应器"/>
<TextView
android:id="@+id/orientationSensor_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="方向传感器"/>
<TextView
android:id="@+id/adjust_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textColor="@color/red"
android:text="compass"/>
<com.example.mycompass.MiCompass
android:id="@+id/miui"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:background="@color/black"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints" />
</LinearLayout>
<!--<com.example.mycompass.MiCompass
android:id="@+id/miui"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:background="@color/black"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints" />-->
</androidx.constraintlayout.widget.ConstraintLayout>
5、MainActivity.java文件
package com.example.mycompass;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import java.util.List;
public class MainActivity extends AppCompatActivity {
public static final int SENSOR_STATUS_NO_CONTACT = -1;
public static final int SENSOR_STATUS_UNRELIABLE = 0;
public static final int SENSOR_STATUS_ACCURACY_LOW = 1;
/**
* This sensor is reporting data with an average level of accuracy,
* calibration with the environment may improve the readings
*/
public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2;
/** This sensor is reporting data with maximum accuracy */
public static final int SENSOR_STATUS_ACCURACY_HIGH = 3;
private SensorManager mSensorManager;
private MySensorEventListener mMySensorEventListener;
private MiCompass miui;
private float val;
private float[] mAccelerometerReading = new float[3];
private float[] mMagneticFieldReading = new float[3];
private TextView mAccelerometerSensorTextView;
private TextView mMagneticSensorTextView;
private TextView mGyroscopeSensorTextView;
private TextView mOrientationSensorTextView;
private TextView mAdjustTextView;
private String Tag = "Tag:";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAccelerometerSensorTextView = findViewById(R.id.accSensor_tv);
mMagneticSensorTextView = findViewById(R.id.mangeticSensor_tv);
mGyroscopeSensorTextView = findViewById(R.id.gyroscopeSensor_tv);
mOrientationSensorTextView = findViewById(R.id.orientationSensor_tv);
mAdjustTextView = findViewById(R.id.adjust_tv);
miui = findViewById(R.id.miui);
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
this.mMySensorEventListener = new MySensorEventListener();
Sensor accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Sensor magneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
Sensor gyroscopeSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
if (accelerometerSensor != null) {
System.out.println("传感器存在");
Log.d(Tag, "传感器存在");
} else {
System.out.println("传感器不存在");
Log.d(Tag, "传感器不存在");
}
mSensorManager.registerListener(mMySensorEventListener,mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(mMySensorEventListener,accelerometerSensor,
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(mMySensorEventListener,magneticSensor,
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(mMySensorEventListener,gyroscopeSensor,
SensorManager.SENSOR_DELAY_UI);
}
@Override
protected void onDestroy() {
super.onDestroy();
mSensorManager.unregisterListener(mMySensorEventListener);
}
private void calculateOrientation() {
final float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrix(rotationMatrix, null, mAccelerometerReading, mMagneticFieldReading);
final float[] orientationAngles = new float[3];
SensorManager.getOrientation(rotationMatrix, orientationAngles);
System.out.println("orientation data[x:" + orientationAngles[0] + ", y:" + orientationAngles[1] + ", z:" + orientationAngles[2] + "]");
mOrientationSensorTextView.setText("orientation [x:" + orientationAngles[0] + ", y:" + orientationAngles[1] + ", z:" + orientationAngles[2] + "]");
}
private class MySensorEventListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
val = event.values[0];
System.out.println(val);
miui.setVal(val);
} else if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mAccelerometerReading = event.values;
System.out.println("accelerometer data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
// Log.d(Tag, "accelerometer data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
mAccelerometerSensorTextView.setText("accelerometer [x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
} else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
mMagneticFieldReading = event.values;
System.out.println("magnetic data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
// Log.d(Tag, "magnetic data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
mMagneticSensorTextView.setText("magnetic [x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
} else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
System.out.println("gyroscope data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
// Log.d(Tag, "gyroscope data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
mGyroscopeSensorTextView.setText("gyroscope [x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
}
calculateOrientation();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
System.out.println("onAccuracyChanged:" + sensor.getType() + "->" + accuracy);
if (accuracy >= SensorManager.SENSOR_STATUS_ACCURACY_HIGH ) {
System.out.println("Compass, 不需要校验");
// Log.e("Compass", " 不需要校验");
mAdjustTextView.setText("Compass, 不需要校验");
} else {
System.out.println("Compass, 需要校准 ");
// Log.e("Compass", " 需要校准 ");
mAdjustTextView.setText("Compass, 需要校验, 拿手机画8");
}
}
}
}
6、AndroidManifest.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mycompass">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyCompass">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<!-- 添加下面这句话 -->
<uses-feature
android:name="android.hardware.sensor.accelerometer"
android:required="true" />
</manifest>
三、结果
四、总结
在此,做个笔录,没想到多年没碰Android,现在还是初恋的感觉 哈哈^_^。在这希望能帮到各个技术攻城狮。基本多部分都是参考以下文章编写而成,在此非常感谢!这位大佬无私贡献。
源码(csdn代码仓库):Ch_champion / MyCompass · CODE CHINA
参考文章:
相关文章
- Android应用如何开机自启动、自启动失败原因
- Android实例-自定义程序名称、图标、全屏和可旋转方向(XE8+小米2)
- android Notification定义与应用
- Android Studio常用快捷键
- Android API之android.widget.Filterable
- Android开发学习---使用Intelij idea 13.1 进行android 开发
- android 关于插件包内的依赖版本不一致问题得解决
- Android多媒体开发--资源文件播放
- EasyPlayer Android RTSP播放器延迟再优化策略
- Android开发学习---使用Intelij idea 13.1 进行android 开发
- Android--paint应用举例
- 《Android源码设计模式》--单例模式
- [工具] 护眼宝 – 傻瓜版屏幕蓝光过滤应用[Win/Android]
- Android 系统如何预装第三方应用以及常见问题汇集
- android v4l2-ctl工具测试验证Camera摄像头
- Android 水平柱状图(MPAndroidChart框架)
- Android的约束布局constraintlayout
- android 11.0 12.0app应用卸载黑名单
- Android app应用开发高级进阶系列专栏解读
- 【Android 安装包优化】7z 文件压缩格式 ( 7z 格式简介 | 7z 命令使用说明 )
- 【Android 应用开发】Android 开发环境下载地址 -- 百度网盘 adt-bundle android-studio sdk adt 下载
- 爱加密Android APk 原理解析
- 解决android模块化升级方法
- Android培训班(61)dex文件格式2
- Android 系统休眠唤醒 android-suspend