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) {

}

}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐