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

来源:互联网 发布:软件项目介绍ppt 编辑:程序博客网 时间:2024/05/21 06:40

概述:

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 0
原创粉丝点击