概述:
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);
}
}
结果演示(必须在真机上才能运行):
看到没,我的指北针多么简约大气。
我们猿类工作压力大,很需要有自己的乐趣,于是乎,我开通了音乐人账号,以后的作品将会上传到我的音乐人小站上。如果这篇博客帮助到您,希望您能多关注,支持,鼓励我将创作进行下去,同时也祝你能在工作和生活乐趣两发面都能出彩!