Android 实现指南针效果
前一段时间在做指南针,于是想偷偷懒.在网上直接找一个Demo.然后改改旧差不多了.可是看到的效果却和预期的差太多了,所以就不得不自己撸一个:
大致上会用到内容
- 自定义View
- GPS定位模块
- 方向传感器
开始,创建一个view
先写一个类继承view
不断对OnDraw事件进行重绘
传入方向
OK.那么新建一个DirectionView 来继承view public class DirectionView extends View {
}
那么绘制需要用到什么。用到画笔。宽度。等等一系列参数。 public class DirectionView extends View {
/**
* 圆环使用
* */
private Paint mRingPaint;
private Paint mCententPaint; //绘制中心实线的画布
/**
* 圆环半径 根据view的宽度计算
* */
private int mRadius = 200;
/**
* 圆环的中心点 -- 画圆环和旋转画布时需要使用
* */
private int x, y;
/**
* 圆环动画使用 -- 与mRingPaint唯一不同得方在于颜色
* */
private Paint mRingAnimPaint;
/**
* 圆环大小 矩形
* */
private RectF mRectf;
private Context mContext;
/**
* 圆环 宽度
* */
private final int mHeartPaintWidth = 50;
/**
* 圆环动画开始时 画弧的偏移量
* */
private int mAnimAngle = -1;
}
初始化部分我们先不管。看到效果图.我们是不是需要先将360度的齿轮画好。
这里我们就需要对ondraw 来操作了。
绘制嘛。必须要画板嘛
canvas.setDrawFilter(mDrawFilter);//在canvas上抗锯齿
//由于drawArc默认从x轴开始画,因此需要将画布旋转或者绘制角度旋转,2种方案
//int level = canvas.save();
//先绘制竖线
canvas.drawLine(x,mRectf.top + 30, x , mRectf.top - 60,mCententPaint);
//绘制中心线
canvas.drawLine(x,y-80,x,y + 80,mCententPaint);
canvas.drawLine(x - 80,y,x + 80, y ,mCententPaint);
canvas.rotate(rotate, x, y);// 旋转的时候一定要指明中心
for (int i = 0; i < 360; i += 3) {
canvas.drawArc(mRectf, i, 1, false, mRingPaint);
}
这里喔们把360度的齿轮绘制了。大致上是每隔3度绘制一条。
那么绘制齿轮之后。我们是不是需要绘制东西南北了。
mCententPaint.setTextSize(50);
mCententPaint.setColor(Color.RED);
canvas.drawText("北",x,mRectf.top + mHeartPaintWidth + 50,mCententPaint);
mCententPaint.setColor(Color.BLACK);
canvas.rotate(90, x, y);// 旋转的时候一定要指明中心
canvas.drawText("东",x,mRectf.top + mHeartPaintWidth + 50,mCententPaint);
canvas.rotate(90, x, y);// 旋转的时候一定要指明中心
canvas.drawText("南",x,mRectf.top + mHeartPaintWidth + 50,mCententPaint);
canvas.rotate(90, x, y);// 旋转的时候一定要指明中心
canvas.drawText("西",x,mRectf.top + mHeartPaintWidth + 50,mCententPaint);
canvas.rotate(90, x, y);// 旋转的时候一定要指明中心
mCententPaint.setTextSize(30);
for (int i = 0; i < 360; i += 3) {
if(i == 0|| i == 30 || i ==60 || i ==90 || i ==120 || i == 150 || i == 180 || i == 210 || i == 240 || i == 270 || i == 300 || i == 330 || i== 0){
canvas.drawText(""+i,x,mRectf.top - mHeartPaintWidth ,mCententPaint);
canvas.rotate(30, x, y);// 旋转的时候一定要指明中心
}
}
那么整个代码就是:
package com.jonkming.easyui.hardware.compass.ui;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DrawFilter;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.jonkming.easyui.R;
/**
* 指南针的自定位View
*@Title: DirectionView.java
*@Package com.jonkming.easyui.hardware.compass.ui
*@author HuangMingming
*@date 2016/11/10 19:16
*@version V1.0
*/
public class DirectionView extends View {
/**
* 圆环使用
* */
private Paint mRingPaint;
private Paint mCententPaint; //绘制中心实线的画布
/**
* 圆环半径 根据view的宽度计算
* */
private int mRadius = 200;
/**
* 圆环的中心点 -- 画圆环和旋转画布时需要使用
* */
private int x, y;
/**
* 圆环动画使用 -- 与mRingPaint唯一不同得方在于颜色
* */
private Paint mRingAnimPaint;
/**
* 圆环大小 矩形
* */
private RectF mRectf;
private Context mContext;
/**
* 圆环 宽度
* */
private final int mHeartPaintWidth = 50;
/**
* 圆环动画开始时 画弧的偏移量
* */
private int mAnimAngle = -1;
public DirectionView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
this.mContext = context;
init();
}
public DirectionView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
this.mContext = context;
init();
}
public DirectionView(Context context)
{
this(context, null);
this.mContext = context;
init();
}
private void init(){
mRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRingPaint.setStrokeWidth(mHeartPaintWidth);
mRingPaint.setStyle(Paint.Style.STROKE);
mRingAnimPaint = new Paint(mRingPaint);
mRingAnimPaint.setColor(Color.WHITE);
//初始化心跳曲线
mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
mCententPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCententPaint.setColor(Color.BLACK);
mCententPaint.setStrokeWidth(3);
}
/**
* canvas抗锯齿开启需要
* */
private DrawFilter mDrawFilter;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
x = w / 2;
y = h / 2;
mRadius = w / 2 - mHeartPaintWidth * 3; //因为制定了Paint的宽度,因此计算半径需要减去这个
mRectf = new RectF(x - mRadius, y - mRadius, x + mRadius, y + mRadius);
}
public float rotate = 0;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.setDrawFilter(mDrawFilter);//在canvas上抗锯齿
//由于drawArc默认从x轴开始画,因此需要将画布旋转或者绘制角度旋转,2种方案
//int level = canvas.save();
//先绘制竖线
canvas.drawLine(x,mRectf.top + 30, x , mRectf.top - 60,mCententPaint);
//绘制中心线
canvas.drawLine(x,y-80,x,y + 80,mCententPaint);
canvas.drawLine(x - 80,y,x + 80, y ,mCententPaint);
canvas.rotate(rotate, x, y);// 旋转的时候一定要指明中心
for (int i = 0; i < 360; i += 3) {
canvas.drawArc(mRectf, i, 1, false, mRingPaint);
}
mCententPaint.setTextSize(50);
mCententPaint.setColor(Color.RED);
canvas.drawText("北",x,mRectf.top + mHeartPaintWidth + 50,mCententPaint);
mCententPaint.setColor(Color.BLACK);
canvas.rotate(90, x, y);// 旋转的时候一定要指明中心
canvas.drawText("东",x,mRectf.top + mHeartPaintWidth + 50,mCententPaint);
canvas.rotate(90, x, y);// 旋转的时候一定要指明中心
canvas.drawText("南",x,mRectf.top + mHeartPaintWidth + 50,mCententPaint);
canvas.rotate(90, x, y);// 旋转的时候一定要指明中心
canvas.drawText("西",x,mRectf.top + mHeartPaintWidth + 50,mCententPaint);
canvas.rotate(90, x, y);// 旋转的时候一定要指明中心
mCententPaint.setTextSize(30);
for (int i = 0; i < 360; i += 3) {
if(i == 0|| i == 30 || i ==60 || i ==90 || i ==120 || i == 150 || i == 180 || i == 210 || i == 240 || i == 270 || i == 300 || i == 330 || i== 0){
canvas.drawText(""+i,x,mRectf.top - mHeartPaintWidth ,mCententPaint);
canvas.rotate(30, x, y);// 旋转的时候一定要指明中心
}
}
}
}
绘制完了之后我们是不是要写界面代码了。这里xml 布局就不贴出来了。后面可以直接去github 去看看
主界面主要的作用就是对sensor监听。并返回方向的角度。然后对上面定义的view进行方向赋值。然后通知view 重绘就可以了
@Override
protected void onResume() {
/**
* 获取方向传感器
* 通过SensorManager对象获取相应的Sensor类型的对象
*/
Sensor sensor = manager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
//应用在前台时候注册监听器
manager.registerListener(listener, sensor,
SensorManager.SENSOR_DELAY_GAME);
super.onResume();
}
@Override
protected void onPause() {
//应用不在前台时候销毁掉监听器
manager.unregisterListener(listener);
super.onPause();
}
private final class SensorListener implements SensorEventListener {
private float predegree = 0;
@Override
public void onSensorChanged(SensorEvent event) {
/**
* values[0]: x-axis 方向加速度
values[1]: y-axis 方向加速度
values[2]: z-axis 方向加速度
*/
float degree = event.values[0];// 存放了方向值
predegree=-degree;
mCompassDegreeTxt.setText(""+((int)degree)+"°");
mCompassDirectionTxt.setText(formatPredegree(degree));
directionView.rotate = predegree;
directionView.postInvalidate();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}