一、对SurfaceView 的认识:
在Android中,SurfaceView是View的子类,它内嵌了一个专门用于绘制的Surface,我们可以控制这个Surface的格式和尺寸,Surfaceview控制这个Surface的绘制位置。surface是纵深排序(Z-ordered)的,说明它总在自己所在窗口的后面。SurfaceView提供了一个可见区域,只有在这个可见区域内的surface内容才可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面有透明控件,那么每次surface变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。SurfaceView默认使用双缓冲技术的,它支持在子线程中绘制图像,这样就不会阻塞主线程了,所以它更适合于游戏的开发。
SurfaceView使用的方式与任何View所派生的类都是完全相同的。可以像其他View那样应用动画,并把它们放到布局中。SurfaceView封装的Surface支持所有标准的Canvas方法进行绘图,同时也支持完全的OpenGL ES 库。
二、创建SurfaceView控件:
首先我们需要继承SurfaceView并实现SurfaceHolder.Callback接口,这是因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始(Surface—表面,这个概念在 图形编程中常常被提到。基本上我们可以把它当作显存的一个映射,写入到Surface 的内容可以被直接复制到显存从而显示出来,这使得显示速度会非常快),而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。接着我们需要实现它的3个方法:
1. surfaceCreated(SurfaceHolder holder):surface创建的时候调用,一般在该方法中启动绘图的线程。
2. surfaceChanged(SurfaceHolder holder, int format, int width,int height):surface尺寸发生改变的时候调用,如横竖屏切换。
3. surfaceDestroyed(SurfaceHolder holder) :surface被销毁的时候调用,如退出游戏画面,一般在该方法中停止绘图线程。
同时,我们还需要获得SurfaceHolder,并添加回调函数holder.addCallback(this);,这样这三个方法才会执行。另外,在绘制时,锁定画布,画布用完后要释放holder.unlockCanvasAndPost(canvas);
Android 简单动画的代码:
MainActivity.java
package com.example.cartoon;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化SurfaceView
BallSurfaceView sv = new BallSurfaceView(this);
setContentView(sv);
}
}
BallSurfaceView.java
package com.example.cartoon;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class BallSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable{
private SurfaceHolder holder;
private boolean runFlag;
private Paint paint = new Paint();
//重写构造方法
public BallSurfaceView(Context context) {
this(context, null);
}
public BallSurfaceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BallSurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//获取Surface句柄对象,通过该对象获取画布
holder = this.getHolder();
//添加回调接口
holder.addCallback(this);
// setFocusable(true);
}
//实现SurfaceHolder.Callback接口的方法
@Override//当切换横竖屏时调用
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
//当SurfaceView创建时调用
@Override
public void surfaceCreated(SurfaceHolder arg0) {
//创建时启动线程
runFlag = true;
new Thread(this).start();
}
//当SurfaceView结束时调用
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
//退出时结束线程
runFlag = false;
}
//重写run方法
@Override
public void run() {
int x = 0;
int y = 0;
int dx = 2;
int dy = 3;
int width = 30;
int height = 30;
while(runFlag){
Canvas canvas = null;
try {
//锁定画笔对象
canvas = holder.lockCanvas();
//设置画笔
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
//填充背景颜色
Rect rect = new Rect(0, 0, this.getWidth(), this.getHeight());
canvas.drawRect(rect, paint);
//绘制小球,设置小球颜色为红
paint.setColor(Color.RED);
RectF rf = new RectF(x, y, x+width, y+height);
canvas.drawOval(rf, paint);
//小球移动
x += dx;
y += dy;
//边界判断
if(x<=0 || x>=this.getWidth()){
dx = -dx;
}
if(y<=0 || y>=this.getHeight()){
dy = -dy;
}
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
//画布用完要释放
if(canvas != null){
holder.unlockCanvasAndPost(canvas);
}
}
}
}
}