SurfaceView是简单高效的用于渲染图形的类,适合用于简单的2D游戏开发。
本文介绍了Android中SurfaceView的使用,包括使用SurfaceView绘制单个图形,多个图形,组合图形,并使组合图形移动。
详细代码:github.com/Baolvlv/LearnAndroid/tree/master/SurfaceView
surfaceView主要用于游戏开发,当view需要频繁绘制时,会消耗很多资源,这时可以使用surfaceview进行。同时surfaceviwe可以在主线程之外的线程中进行。当画面需要被动更新时(靠事件触发,例如棋牌类游戏),可以使用view,而需要主动更新时,则选择surfaceview
1.SurfaceView的使用
创建一个类继承自SurfaceViwe,并实现SurfaceHolder.Callback接口,实现构造函数与借口的三个方法
publicMyView(Context context) {
super(context);
//添加回调函数
getHolder().addCallback(this);
}
//surface创建时执行
@Override
public voidsurfaceCreated(SurfaceHolder holder) {
}
//surface改变时执行
@Override
public voidsurfaceChanged(SurfaceHolder holder, intformat, intwidth, intheight) {
}
//surface意外销毁时执行
@Override
public voidsurfaceDestroyed(SurfaceHolder holder) {
}
//创建画布,图形开始时锁定画布,图形结束后解锁画布
Canvas canvas = getHolder().lockCanvas();
getHolder().unlockCanvasAndPost(canvas);
2.SurfaceView绘制单个图形
声明化画笔,在构造方法中初始化并设置画笔颜色
//声明画笔
privatePaintpaint=null;
paint=newPaint();
paint.setColor(Color.RED);
在自定义的Draw方法中,设置画布颜色并绘制图形
public voiddraw(){
//创建画布,图形开始时锁定画布,图形结束后解锁画布
Canvas canvas = getHolder().lockCanvas();
//设置画布颜色
canvas.drawColor(Color.WHITE);
//绘制长100宽100的矩形
canvas.drawRect(0,0,100,100,paint);
getHolder().unlockCanvasAndPost(canvas);
}
在surfaceCreate方法中调用绘制方法
public voidsurfaceCreated(SurfaceHolder holder) {
draw();
}
在MainActivity的onCreate方法中添加View
setContentView(newMyView(this));
3.SurfaceView绘制多个图形
直接调用canvas不断绘制即可绘制多个图形
当需要对其中的一个图形进行旋转,剪切等变换时,canvas.save与canvas.restore配合使用,用以不影响其他图形,旋转是通过旋转画布实现
canvas.save();
canvas.rotate(90,getWidth()/2,getHeight()/2);
canvas.drawLine(0,getHeight()/2,getWidth(),getHeight(),paint);
//还原画布
canvas.restore();
4.SurfaceView绘制组合图形
绘制组合图形有三个要点:
1.需要一个抽象的容器类,其子类为各种具体的图形,同时包含List储存各种子类图形
2.画布在主SurfaceView中设置好后,在逐级容器间传递
3.每个类得到画布后,绘制自己的图形
步骤:
自定义Container类,设置用于储存的List并在构造函数中初始化
public classContanier {
//储存子容器的List
privateListchildren=null;
//构造函数,实例化list
publicContanier(){
children=newArrayList();
}
编写向list中添加与删除view方法
//添加子view方法
public voidaddChildernView(Contanier child){
children.add(child);
}
//移除子view方法
public voidremoveChidernView(Contanier child){
children.remove(child);
}
编写向子容器传递画布并绘制其独特图形的方法,之后在子容器中进行复写
//向子容器传递画布并且子容器完成自己的绘制
public voidchildernViewCanvasAndDraw(Canvas canvas){
}
编写向逐级子容器传递画布的方法
//将画布传递给子容器,同时为容器内list中所有的子容器设置画布
public voidsetCanvas(Canvas canvas){
childernViewCanvasAndDraw(canvas);
for(Contanier c :children){
c.setCanvas(canvas);
}
编写具体图形类,继承自Contanier,作为容器可嵌套,构造函数初始化画笔
public classRectextendsContanier{
privatePaintpaint=null;
//构造函数初始化画笔
publicRect(){
paint=newPaint();
paint.setColor(Color.RED);
}
重写父类方法,接收画布绘制图形
public voidchildernViewCanvasAndDraw(Canvas canvas){
super.childernViewCanvasAndDraw(canvas);
canvas.drawRect(0,0,100,100,paint);
}
主surfaceView构造函数中实例化contanier及具体图形
privateContaniercontanier;
privateRectrect;
privateCirclecircle;
contanier=newContanier();
rect=newRect();
circle=newCircle();
rect.addChildernView(circle);
contanier.addChildernView(rect);
设置画布,并调用contanier类的方法传递画布
//创建画布,图形开始时锁定画布,图形结束后解锁画布
Canvas canvas = getHolder().lockCanvas();
//设置画布颜色
canvas.drawColor(Color.WHITE);
//为所有容器统一设置画布
contanier.setCanvas(canvas);
getHolder().unlockCanvasAndPost(canvas);
5.使组合图形移动
通过x,y坐标完成移动,首先设置x,y坐标变量
//设置坐标
private floatx=0,y=0;
get和set方法
//get和set方法
public voidsetX(floatx) {
this.x= x;
}
public floatgetX() {
returnx;
}
public voidsetY(floaty) {
this.y= y;
}
public floatgetY() {
returny;
}
在contanier类中为子容器逐级设置画布的方法中进行移动
在canvas的save与restore方法中,进行画布移动
/通过save和restore进行移动变化
canvas.save();
//根据当前的x,y坐标移动画布
canvas.translate(getX(),getY());
childernViewCanvasAndDraw(canvas);
for(Contanier c :children){
c.setCanvas(canvas);
}
canvas.restore();
在最外层的矩形子类中,绘制图形后,当前纵坐标增加1,作为下一次绘制时的纵坐标,实现不断移动
//不断增加画布移动坐标
this.setY(getY() +1);
在主surfaceView中,设置timer与timerTask,进行不断绘制
//创建计时器与计时器任务对象
privateTimertimer=null;
privateTimerTasktask=null;
//开始计时器方法
public voidstartTimer(){
timer=newTimer();
task=newTimerTask() {
//实例化timertask,复写run方法,不断进行绘制
@Override
public voidrun() {
draw();
}
};
//timer执行timerTask,100毫米后开始,每100毫秒执行一次
timer.schedule(task,100,100);
}
//停止计时器
public voidstopTimer(){
//当计时器不为空时,取消计时器,并设置为空
if(timer!=null){
timer.cancel();
timer=null;
}
在surfaceCreate方法中,开始计时器,在surfaceDestoryed方法中,停止计时器,否则会引发异常
//surface创建时执行
@Override
public voidsurfaceCreated(SurfaceHolder holder) {
startTimer();
}
//surface意外销毁时执行
@Override
public voidsurfaceDestroyed(SurfaceHolder holder) {
//surface结束之后不停止timer,会出现异常
stopTimer();
}