自从写完那个自定义菊花加载view后,又想着来一个类似的,这种知识点可以用在很多地方,如果手表,水表、还有今天要说的指南针等,只要是带刻度的都可以。
首先我们考虑下这个指南针要包括什么:
1、方位角刻度:也就是我当前位置和目的位置的方位角,方位角是与北方向相比偏离的角度。
2、东南西北不同颜色区分
3、根据手的水平移动,指南针view也要对应移动
获取指南针角度,可用SensorManager,这个是个系统服务,即可实时获取当前指向角度了。注册代码:
if(sensorManager==null){
sensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE);
//通过 getDefaultSensor 获得指南针传感器
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
//为传感器管理者注册监听器,第三个参数指获取速度正常
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);
}
这里我注册的是SENSOR_DELAY_GAME,游戏级别的传感器,之前我用的是SENSOR_DELAY_NORMAL默认的,感觉没游戏级别的好。
画刻度还是老样子,for循环360度,每一度画一个刻度,画完后将canvas旋转一度
for (int i = 0; i < 360; i++) {
canvas.drawLine(x, y - r, x, (float) (y - r + x * 0.2), mPaint);
canvas.rotate(360 / 360, x, y);
}
至于其他特别的刻度比如红色刻度、长一些的刻度,我们可以做判断也可以另起for循环画,达到覆盖他的效果。话不多说直接上源码:
public class DemoZhiNaZhen extends View implements SensorEventListener {
private int mWidth;
private int mHeigth;
private Sensor sensor;
private SensorManager sensorManager;
private int toDegrees;
private Paint mPaint;
public void setCureentAngla(int mCureentAngla) {
this.mCureentAngla = mCureentAngla;
if(sensorManager==null){
sensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE);
//通过 getDefaultSensor 获得指南针传感器
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
//为传感器管理者注册监听器,第三个参数指获取速度正常
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);
}
}
private int mCureentAngla=181;
private Paint mBitmapPaint;
private Paint mTextPaint;
private Context context;
public DemoZhiNaZhen(Context context) {
this(context, null);
}
public DemoZhiNaZhen(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DemoZhiNaZhen(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context=context;
mPaint = new Paint();
mPaint.setDither(true);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.GRAY);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(getResources().getDimension(R.dimen.dp_1));
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mBitmapPaint = new Paint();
mBitmapPaint.setDither(true);
mBitmapPaint.setAntiAlias(true);
mTextPaint = new Paint();
mTextPaint.setDither(true);
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(Color.GRAY);
mTextPaint.setTextSize(getResources().getDimension(R.dimen.sp_12));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeigth = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(mWidth, mHeigth);
}
@Override
protected void onDraw(Canvas canvas) {
int x = mWidth / 2;
int y = mHeigth / 2;
int r = (int) (mWidth * 0.42);
canvas.save();
for (int i = 0; i < 120; i++) {
if(i==0){
mPaint.setColor(Color.RED);
drawText("北",canvas);
canvas.drawLine(x, y - r, x, (float) (y - r + x * 0.1), mPaint);
}else if(i==30){
mPaint.setColor(Color.RED);
drawText("东",canvas);
canvas.drawLine(x, y - r, x, (float) (y - r + x * 0.1), mPaint);
}else if(i==60){
mPaint.setColor(Color.RED);
drawText("南",canvas);
canvas.drawLine(x, y - r, x, (float) (y - r + x * 0.1), mPaint);
}else if(i==90){
mPaint.setColor(Color.RED);
drawText("西",canvas);
canvas.drawLine(x, y - r, x, (float) (y - r + x * 0.1), mPaint);
}else if(i==5||i==10||i==20||i==25||i==15||i==35||i==40||i==45||i==50||i==55||i==65||i==70||i==75||i==80||i==85||i==95||i==100||i==105||i==110||i==115){
mPaint.setColor(Color.BLACK);
drawText(i*3+"",canvas);
canvas.drawLine(x, y - r, x, (float) (y - r + x * 0.1), mPaint);
}else{
//绘制下层菊花
mPaint.setColor(Color.GRAY);
canvas.drawLine(x, y - r, x, (float) (y - r + x * 0.1), mPaint);
}
canvas.rotate(360 / 120, x, y);
}
for (int i = 0; i < 360; i++) {
if(mCureentAngla==i){
canvas.drawLine(x, y - r, x, (float) (y - r + x * 0.2), mPaint);
}
canvas.rotate(360 / 360, x, y);
}
canvas.restore();
}
public void drawText(String string,Canvas canvas){
//画中间文字
String text = string;
Rect textRect=new Rect();
mTextPaint.getTextBounds(text,0,text.length(),textRect);
int startX=getWidth()/2-textRect.width()/2;
int textHeight=textRect.height();
int baseLine=0;
Paint.FontMetricsInt fontMetricsInt = mTextPaint.getFontMetricsInt();
int dy=(fontMetricsInt.bottom-fontMetricsInt.top)/2-fontMetricsInt.bottom;
baseLine= textHeight/2+dy;
canvas.drawText(text,startX,baseLine,mTextPaint);
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
switch (sensorEvent.sensor.getType()) {
case Sensor.TYPE_ORIENTATION:
//顺时针转动为正,故手机顺时针转动时,图片得逆时针转动
toDegrees = (int) -sensorEvent.values[0];
if( this.onAnglaChanged !=null){
onAnglaChanged.onChanged(toDegrees);
}
break;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if(sensorManager!=null){
sensorManager.unregisterListener(this);
}
}
public interface OnAnglaChanged{
void onChanged(int angla);
}
public OnAnglaChanged onAnglaChanged;
public void setOnAnglaChanged(OnAnglaChanged onAnglaChanged){
this.onAnglaChanged=onAnglaChanged;
}
}
可以看到代码里面我留了setCureentAngla这个接口,这就是设置当前方位角的,我把求方位角的代码留在了activity中这不算是很好的封装(吃瓜群众:偷懒就是偷懒,还这么多借口)。
好吧,我承认是有那么一丢丢懒,但是我不改,哈哈哈。
下面是activity中的使用代码:
public class Main19Activity extends AppCompatActivity {
private DemoZhiNaZhen test;
private int fromDegrees = 0;
private TextView mTvAngla;
//31.2036,121.6012
//31.1237,121.3536
private PointF start = new PointF(31.1237f, 121.3536f);//起点
private PointF end = new PointF(31.2036f, 121.6012f);//起点
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main19);
test = (DemoZhiNaZhen) findViewById(R.id.test);
mTvAngla = (TextView) findViewById(R.id.tv_angla);
test.setCureentAngla((int) gps2d(31.1237f, 121.3536f, 31.2036f, 121.6012f));
test.setOnAnglaChanged(new DemoZhiNaZhen.OnAnglaChanged() {
@Override
public void onChanged(int toDegrees) {
mTvAngla.setText("" + Math.abs(toDegrees) + " 度");
//让图片相对自身中心点转动,开始角度默认为0;此后开始角度等于上一次结束角度
RotateAnimation ra = new RotateAnimation(fromDegrees,
toDegrees, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
ra.setInterpolator(new LinearInterpolator());
//动画时间200毫秒
ra.setDuration(Math.abs(fromDegrees-toDegrees));
ra.setFillAfter(true);
test.startAnimation(ra);
fromDegrees = toDegrees;
}
});
}
private float gps2d(float lat_a, float lng_a, float lat_b, float lng_b) {
float d = 0;
lat_a = (float) (lat_a * Math.PI / 180);
lng_a = (float) (lng_a * Math.PI / 180);
lat_b = (float) (lat_b * Math.PI / 180);
lng_b = (float) (lng_b * Math.PI / 180);
d = (float) (Math.sin(lat_a) * Math.sin(lat_b) +
Math.cos(lat_a) * Math.cos(lat_b) * Math.cos(lng_b - lng_a));
d = (float) Math.sqrt(1 - d * d);
d = (float) (Math.cos(lat_b) * Math.sin(lng_b - lng_a) / d);
d = (float) (Math.asin(d) * 180 / Math.PI);
System.out.println("yanjin-------方位角--" + d);
return d;
}
}
效果图: