SurfaceView 是在子线程中更新画面的组件, View是 在 UI 的主线程中更新画面, 适合于做动画.
使用SurfaceView 通常要实现 SurfaceHolder.Callback接口,SurfaceView 类的生命周期有3个回调函数,分别为:
public abstract void surfaceCreated(SurfaceHolder holder) 在SurfaceView 创建时调用
public abstract void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 在SurfaceView 改变时调用
public abstract void surfaceDestroyed(SurfaceHolder holder)在SurfaceView 销毁前调用
此外, 还有一个重要方法:
protected void onDraw(Canvas c) 用来绘制SurfaceView 画面, 每一次SurfaceView 中画面改变都是调用此方法.
通常实现动画效果原理是:
新建一个线程类,每隔一段时间调用SurfaceView 的onDraw(), 在onDraw() 方法中的画面也有一个线程类在时刻改变,这样后一个线程类实现了onDraw() 画面中显示内容的变化, 前一个线程类 时刻刷新画面,这样就形成了动画.
具体代码请参见 SufaceView_3_7 工程, 讲解一下两个线程类
使用SurfaceView 通常要实现 SurfaceHolder.Callback接口,SurfaceView 类的生命周期有3个回调函数,分别为:
public abstract void surfaceCreated(SurfaceHolder holder) 在SurfaceView 创建时调用
public abstract void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 在SurfaceView 改变时调用
public abstract void surfaceDestroyed(SurfaceHolder holder)在SurfaceView 销毁前调用
此外, 还有一个重要方法:
protected void onDraw(Canvas c) 用来绘制SurfaceView 画面, 每一次SurfaceView 中画面改变都是调用此方法.
通常实现动画效果原理是:
新建一个线程类,每隔一段时间调用SurfaceView 的onDraw(), 在onDraw() 方法中的画面也有一个线程类在时刻改变,这样后一个线程类实现了onDraw() 画面中显示内容的变化, 前一个线程类 时刻刷新画面,这样就形成了动画.
具体代码请参见 SufaceView_3_7 工程, 讲解一下两个线程类
public class OnDrawThread extends Thread {
MySurfaceView msv; // 得到MySurfaceView的引用
SurfaceHolder sh; // SurfaceHolder引用
public OnDrawThread(MySurfaceView msv) {
super();
this.msv = msv; // 构造方法中,将msv引用指向调用了该类的MySurfaceView的对象
sh = msv.getHolder();
}
@Override
public void run() {
super.run();
Canvas canvas = null;
while (true) { // 这个循环用于时刻刷新界面
try {
canvas = sh.lockCanvas(null); // 将canvas的引用指向surfaceView的canvas的对象
synchronized (this.sh) { // 绘制过程,可能带来同步方面的问题,加锁
if (canvas != null) {
msv.onDraw(canvas); // 这里调用onDraw(),时刻刷新画面
}
}
} finally {
try {
if (sh != null) {
sh.unlockCanvasAndPost(canvas); // 绘制完后解锁
}
} catch (Exception e) {
e.printStackTrace();
}
}
try {
Thread.sleep(Constant.ONDRAWSPEED); // 休息1秒钟
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
----------------------------------
//该类是控制duke图片运动的类
public class PicRunThread extends Thread{
MySurfaceView msv; //MySurfaceView的引用
private float picX=0; //图片x坐标
private float picY=Constant.SCREENHEIGHT-Constant.PICHEIGHT; //图片y坐标
boolean yRunFlag=false; //y方向上的运动标记,false时y=y+speed,true时y=y-speed
int picAlphaNum=0; //图片变暗效果中画笔的alpha值
public PicRunThread(MySurfaceView msv) {
super();
this.msv = msv; //将该线程类的引用指向调用其的MySurfaceView的对象
}
@Override
public void run() {
super.run();
while(true){ //这个循环用于显示内容变化,实现重复显示, 如果没有则画面只显示一遍
//控制duke图片的运动
while(this.picX<Constant.SCREENWIDTH){ //当图片的左边完全超过屏幕的右边时,循环结束
msv.setPicX(picX);
msv.setPicY(picY);
picX=picX+Constant.PICXSPEED;
if(yRunFlag){//应该向上运动,自减
picY=picY-Constant.PICYSPEED;
}else{//应该向下运动,自加
picY=picY+Constant.PICYSPEED;
}
if(picY<=0){ //到达屏幕上沿
yRunFlag=false;
}else if(picY>Constant.SCREENHEIGHT-Constant.PICHEIGHT){ //到达屏幕下沿
yRunFlag=true;
}
try{
Thread.sleep(Constant.PICRUNSPEED);
}catch(Exception e){e.printStackTrace();}
}
//图片变暗效果演示
msv.picAlphaFlag=true; //开启图片变暗效果
for(picAlphaNum=100;picAlphaNum<=200;picAlphaNum++){
if(picAlphaNum==200){
msv.picAlphaFlag=false; //当图片变暗效果结束,标记重置
picX=0; //图片x坐标
picY=Constant.SCREENHEIGHT-Constant.PICHEIGHT; //图片y坐标
System.out.println(msv.picAlphaFlag+"picX:"+picX+"picY:"+picY);
}
msv.setPicAlphaNum(picAlphaNum);
try{
Thread.sleep(Constant.PICALPHASPEED);
}catch(Exception e){e.printStackTrace();}
}
}
}
}
效果图示意如下: