1.SurfaceView
一般的View通过刷新来重绘视图,Android系统通过发出VSYNC信号来进行屏幕的重绘,刷新的时间间隔是16ms。如果在16ms内View完成了所需要执行的操作,那么用户在视觉上就不会产生卡顿的感觉;而如果执行的逻辑太多,特别是需要频繁刷新的界面,如游戏界面,那么就会不断的阻塞主线程,从而导致界面卡顿。为了避免这种问题,Android提供了SurfaceView来解决这个问题。
SurfaceView和View的区别主要是下面几点:
- View主要适用于主动更行的情况,而SurfaceView适用于被动更新,例如频繁的刷新。
- View在主线程中对画面进行,而SurfaceView通常会在一个子线程中进行页面的刷新
- View在绘图时没有使用双缓冲机制,而SurfaceView在底层实现了双缓冲机制
下面是使用SurfaceView时的模板代码,基本可以满足大部分情况:
public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback,Runnable {
private SurfaceHolder mHolder;
private boolean mIsDrawing;
protected Canvas mCanvas;
public SurfaceViewTemplate(Context context) {
this(context,null);
}
public SurfaceViewTemplate(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setKeepScreenOn(true);
setFocusableInTouchMode(true);
}
@Override
public void run() {
while(mIsDrawing) {
try {
mCanvas = mHolder.lockCanvas();
draw();
} catch (Exception e) {
e.printStackTrace();
}finally {
if (mCanvas != null) {
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
}
protected void draw(){
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsDrawing = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsDrawing = false;
}
}
使用时可以继承自这个模板类,然后重写draw()方法,在里面实现绘制的逻辑。
下面是一个绘制正弦曲线的SurfaceView
public class SinView extends SurfaceViewTemplate {
private Paint mPaint;
private Path mPath;
public SinView(Context context) {
this(context, null);
}
public SinView(Context context, AttributeSet attrs) {
super(context, attrs);
prepare();
}
private void prepare() {
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(10);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPath = new Path();
mPath.moveTo(0,400);
}
int x = 0;
int y = 0;
@Override
protected void draw() {
x+=1;
y = (int) (100 * Math.sin(x * 2 * Math.PI / 180) + 400);
mPath.lineTo(x, y);
mCanvas.drawPath(mPath, mPaint);
}
}
下面的代码是使用SurfaceView实现的画笔功能
public class PaintView extends SurfaceViewTemplate {
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
}
private Paint mPaint;
private Path mPath;
@Override
protected void init() {
super.init();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(20);
mPath = new Path();
}
@Override
protected void draw() {
mCanvas.drawColor(Color.WHITE);
mCanvas.drawPath(mPath, mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath.moveTo(x,y);
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(x, y);
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
}