文章目录
View之兄弟———SurfaceView
1.SurfaceView与View的区别
-
View通过刷新来重绘视图。Android系统通过发出VSYNC信号来绘制屏幕,刷新时间间隔为16ms.
-
如果在16ms内完成View你所需要的操作,那么用户视觉上,就不会产生卡顿。反之,未能完成逻辑操作,就会造成画面卡顿(因此SurfaceView,这时就有用处了)
2.SurfaceView与View的适用场景
- View主要适用主动更新的情况下,而SurfaceView适用在被动更新
- View在主线程中对画面进行刷新,而SurfaceView会通过子线程进行UI刷新
- VIew在绘图时没有使用双缓冲机制,而SurfaceView在底层实现机制中就已经实现了双缓冲机制
3.SurfaceView的使用
3.1 创建SurfaceView子类
创建自定义的 SurfaceView 的子类, 并实现两个接口 ———SurfaceHolder.Callback和Runnable。
public class MySurfaceView extends SurfaceView
implements SurfaceHolder.Callback, Runnable
要实现SurfaceHolder.Callabck接口方法:
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width
, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
要实现Runnable接口方法:
@Override
public void run() {
}
3.2 初始化SurfaceView
在自定义 SurfaceView 的构造方法中,要对SurfaceView初始化。通常要先定义三个成员变量。
//SurfaceHolder
private SurfaceHolder holder;
//用于绘图的Canvas
private Canvas canvas;
//子线程标志
private boolean isDrawing;
//获取父类创建的SurfaceHolder,对holder进行初始化
holder = getHolder();
//注册 SurfaceHolder 的回调方法
holder.addCallback(this);
3.3使用SurfaceView
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import static java.lang.Thread.sleep;
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable{
//SurfaceHolder
private SurfaceHolder holder;
//用于绘图的Canvas
private Canvas canvas;
//用于绘图的画笔
private Paint paint;
//子线程绘制标记
private boolean isDrawing = true;
public MySurfaceView(Context context) {
super(context);
initView();
}
public MySurfaceView(Context context, AttributeSet set) {
super(context, set);
initView();
}
private void initView() {
//获取父类创建的SurfaceHolder,对holder进行初始化
holder = getHolder();
//注册 SurfaceHolder 的回调方法
holder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isDrawing = true;
//子线程中绘制
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isDrawing = false;
}
@Override
public void run() {
int i = 0;
while(isDrawing) {
Log.d("MySurfaceView", "start draw");
draw(i++);
}
}
private void draw(int i) {
if(i == 100) isDrawing = false;
try {
canvas = holder.lockCanvas();
//绘制背景
canvas.drawColor(Color.WHITE);
canvas.drawCircle(250, 250, i, paint);
} catch (Exception e) {
Log.d("MySurfaceView", "draw() Exception");
} finally {
if(canvas != null)
holder.unlockCanvasAndPost(canvas);
}
}
}
3.4正弦曲线
@Override
public void run() {
draw();
x += 1;
y = (int)(100 * Math.sin(x * 2 * Math.PI / 180) + 400);
path.lineTo(x, y);
}
private void draw() {
try {
canvas = holder.lockCanvas();
//SurfaceView背景
canvas.drawColor(Color.WHITE);
canvas.drawPath(path, paint);
} catch (Exception e) {
} finally {
if(canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
3.5绘图板
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(x,y);
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(x, y);
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
@Override
public void run() {
long start = System.currentTimeMillis();
while(isDrawing) {
draw();
}
long end = System.currentTimeMillis();
//50 - 100
if(end - start < 100) {
try {
//优化策略,节省系统资源
Thread.sleep(100 - (end -start));
} catch (InterruptException e) {
e.printStackTrace();
}
}
}
private void draw() {
try {
canvas = holder.lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawPath(path, paint);
} catch (Exception e) {
} finally {
if(canvas != null) holder.unlockCanvasAndPost(canvas);
}
}