Android自定义SurfaceView与传感器的并用(实现自绘的指北针)

概述:

SurfaceView是Android中极为重要的绘图容器,SurfaceView的图像绘制是放在主线程之外的另一个线程中完成的。除了绘图,SurfaceView还能播放视频。

实现方法:

实现Android的自定义SurfaceView,需要新建一个继承于SurfaceView的类,并且重写至少一种构造器,在构造器中,需要同过getHolder()方法得到一个SurfaceViewHolder类的对象holder,canvas画布通过holder调用lockCanvas()方法锁定并得到,用完画布后需要holder调用unlockCanvasAndPost(canvas)方法解锁画布。在构造方法中,holder还必须通过addCallback()方法实现监听器,监听器中需要实现的方法有三个:surfaceCreated()、surfaceChanged()、surfaceDestroyed()。自定义SurfaceView的图像需要在surfaceCreated()方法中绘制。

Demo

用SurfaceView绘制一个指北针的模型,并结合加速度传感器和地磁传感器让它动起来

/**
 * 自定义SurfaceView绘制一个指南针
 * 继承于SurfaceView,并实现它的构造器
 * 实现SurfaceHolder.Callback接口,实现surfaceCreated、surfaceChanged、surfaceDestroyed方法
 */
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{

    private SurfaceHolder holder;
    private Canvas canvas;
    private Path path;

    private Paint mPaintCircle;
    private Paint mPaintLine;
    private Paint mPaintText;

    private int width;
    private int height;
    private float degree;
    private boolean isDrawing = true;

    private SensorManager sensorManager;
    private float lastDegree;

    public float getDegree() {
        return degree;
    }

    public void setDegree(float degree) {
        this.degree = degree;
    }

    public MySurfaceView(Context context) {
        super(context);
    }

    public MySurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);

        width = 1100;
        height = 1500;
        //首先得到一个SurfaceHolder对象
        holder = getHolder();
        //接着让holder添加Callback监听器
        holder.addCallback(this);

        //path用于画指针
        path = new Path();
        //画外环的画笔
        mPaintCircle = new Paint();
        mPaintCircle.setColor(Color.BLACK);
        mPaintCircle.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaintCircle.setStrokeWidth(30);
        //画刻度线的画笔
        mPaintLine = new Paint();
        mPaintLine.setColor(Color.WHITE);
        mPaintLine.setStyle(Paint.Style.FILL);
        mPaintLine.setStrokeWidth(10);
        //画文本的画笔
        mPaintText = new Paint();
        mPaintText.setTextSize(70);
        mPaintLine.setTextAlign(Paint.Align.LEFT);
        mPaintText.setColor(Color.WHITE);

        //sensorManager用于管理传感器
        sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        //地磁传感器
        Sensor magneticSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        //加速度传感器
        Sensor accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        //分别给两种传感器注册监听器
        sensorManager.registerListener(listener, magneticSensor, SensorManager.SENSOR_DELAY_GAME);
        sensorManager.registerListener(listener, accelerometerSensor, SensorManager.SENSOR_DELAY_GAME);

    }

    @Override
    public void surfaceCreated(final SurfaceHolder holder) {
        /**
         * 在一个线程中进行绘制
         */
        new Thread(new Runnable() {
            @Override
            public void run() {
                //用一个无限循环,便于随时改变图形
                while(isDrawing) {
                    canvas = holder.lockCanvas();
                    canvas.drawColor(Color.BLUE);
                    canvas.drawCircle(width / 2, height / 2, 400, mPaintCircle);
                    for (int i = 0; i <= 35; i++) {
                        canvas.save();
                        canvas.rotate(10*i+degree,width / 2, height / 2);
                        canvas.drawLine(width / 2, height / 2 - 400, width / 2, height / 2 - 400 + 50, mPaintLine);
                        if (i == 0) {
                            canvas.drawText("N", width / 2, height / 2 - 400 - 40, mPaintText);
                        }else if(i == 8){
                            canvas.drawText("E" , width / 2, height / 2 -400 -40, mPaintText);
                        }else if(i == 17){
                            canvas.drawText("S" , width / 2, height / 2 -400 -40, mPaintText);
                        }else if(i == 26){
                            canvas.drawText("W" , width / 2, height / 2 -400 -40, mPaintText);
                        }
                        canvas.restore();
                    }
                    //每当degree发生改变,canvas画布都会转动相应的角度
                    canvas.rotate(degree,width / 2, height / 2);

                    //绘制指针
                    path.moveTo(width / 2 - 10, height / 2);
                    path.lineTo(width / 2, height / 2 - 150);
                    path.lineTo(width / 2 + 10, height / 2);
                    path.close();
                    canvas.drawPath(path, mPaintLine);
                    //每次用完canvas,都要调用unlockCanvasAndPost()解锁一次
                    holder.unlockCanvasAndPost(canvas);
                }
            }
        }).start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    /**注销
     * 当调用surfaceDestroyed方法时,停止线程中的死循环,并且sensorManager的监听器
     */
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isDrawing = false;
        if(sensorManager!=null){
            sensorManager.unregisterListener(listener);
        }
    }
    //监听传感器
    private SensorEventListener listener = new SensorEventListener() {
        float[] accelerometerValues = new float[3];
        float[] magneticValues = new float[3];
        @Override
        public void onSensorChanged(SensorEvent event) {
            if(event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
                accelerometerValues = event.values.clone();
            }else if(event.sensor.getType()==Sensor.TYPE_MAGNETIC_FIELD){
                magneticValues = event.values.clone();
            }
            float[] R = new float[9];
            float[] values = new float[3];
            //得到包含旋转矩阵的R数组
            SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticValues);
            //计算手机的旋转数据,并将参数存入values数组
            SensorManager.getOrientation(R, values);
            //将弧度转换为角度
            degree = -(float) Math.toDegrees(values[0]);
            if(Math.abs(degree-lastDegree)>10){
                lastDegree = degree;
            }
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {

        }
    };

}

在xml布局中定义这个自定义SurfaceView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <com.example.administrator.selfishgroupview.my_groupview.MySurfaceView
        android:id="@+id/my_surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

主活动:

public class SouthArrowActivity extends Activity {
    private MySurfaceView mySurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_source);

        mySurfaceView = (MySurfaceView) findViewById(R.id.my_surfaceView);
    }

}

结果演示(必须在真机上才能运行):
这里写图片描述
看到没,我的指北针多么简约大气。

我们猿类工作压力大,很需要有自己的乐趣,于是乎,我开通了音乐人账号,以后的作品将会上传到我的音乐人小站上。如果这篇博客帮助到您,希望您能多关注,支持,鼓励我将创作进行下去,同时也祝你能在工作和生活乐趣两发面都能出彩!

网易云音乐人,直接打开客户端搜索音乐人 “星河河”

豆瓣音乐人地址:https://site.douban.com/chuxinghe/ 星河河

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值