Android 画出来的指南针

自从写完那个自定义菊花加载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;
    }
}

效果图:


1532929065246.gif

你可能感兴趣的:(Android 画出来的指南针)