Android的图形与图像处理之六 SurfaceView实现动画

View存在如下缺陷:
  1. View缺乏双缓冲机制
  2. 程序需要更新View上的图像时,程序必须重绘View上显示的整张图片
  3. 新线程无法直接更新View组件
由于上述缺陷,通过自定义View实现绘图尤其是游戏中的绘图时性能并不好。Android提供了一个SurfaceView来代替View
SurfaceView一般会于SurfaceHolder结合使用,SurfaceHolder用于向与之关联的SurfaceView上绘图,调用SurfaceView的getHolder()方法即可获取SurfaceView关联的SurfaceHolder
SurfaceHolder提供了如下方法来获取Canvas对象:
  • Canvas lockCanvas():锁定整个SurfaceView对象,获取该Surface上的Canvas。
  • Canvas lockCanvas(Rect dirty):锁定SurfaceView上Rect划分的区域,获取该Surface上的Canvas
第二种方法用于获取指定区域的Canvas,只对Rect所指定区域进行更新,这样可以提供画面更新速度
通过lockCanvas()获取指定了SurfaceView上的Canvas之后,接下来程序就可以调用Canvas进行绘图了,Canvas绘图完成后通过如下方法释放绘图、提交所绘制图形:
unlockCanvasAndPost(canvas);
需要注意:调用上述方法后,该方法之前所绘制图形还处于缓冲之中,下一次lockCanvas方法锁定的区域可能会“遮挡”它
View绘图必须在当前UI线程中进行——这也是前面程序需要更新View组件时总要采用Handler处理的原因;而SurfaceView绘图则是由SurfaceHolder来完成的
对于View组件,如果程序需要花较长时间来更新绘图,那么主UI线程将会被阻塞,无法响应用户的动作;而SurfaceViewHolder则会启用新的线程去更新SurfaceView的绘制,因此不会阻塞主UI线程
如果程序需要采用较多定时器控制的动画元素,则可考虑使用SurfaceView,而不是View
示例程序:
main.xml
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:orientation = "vertical"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
>
< LinearLayout android:orientation = "horizontal"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:gravity = "center"
>
< Button android:id = "@+id/sin"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "string/sin"
/>
< Button android:id = "@+id/cos"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "string/cos"
/>
</ LinearLayout >
< SurfaceView android:id = "@+id/show"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:gravity = "center"
/>
</ LinearLayout >
ShowWave.java
public class ShowWave extends ActionBarActivity {

private SurfaceHolder holder ;
private Paint paint ;
final int HEIGHT = 320;
final int WIDTH = 320;
final int X_OFFSET = 5;
private int cx = X_OFFSET ;
int centerY = HEIGHT / 2;
Timer
timer = new Timer();
TimerTask
task = null ;

@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super .onCreate(savedInstanceState);
        setContentView(R.layout.
main );
       
final SurfaceView surface = (SurfaceView)
        findViewById(R.id.
show );
       
holder = surface.getHolder();
       
paint = new Paint();
       
paint .setColor(Color. GREEN );
       
paint .setStrokeWidth(3);
        Button sin = (Button) findViewById(R.id.
sin );
        Button cos = (Button) findViewById(R.id.
cos );
        OnClickListener listener = (
new OnClickListener()
        {
       
@Override
       
public void onClick( final View source)
        {
        drawBack(
holder );
       
cx = X_OFFSET ;
       
if ( task != null )
        {
       
task .cancel();
        }
       
task = new TimerTask()
        {
       
public void run()
        {
       
int cy = source.getId() == R.id. sin ? centerY
        -(
int ) (100 * Math.sin(( cx - 5) * 2 * Math. PI /150))
        :
centerY - ( int ) (100 * Math.cos(( cx -5)*2*Math. PI /150));
        Canvas canvas =
holder .lockCanvas( new Rect( cx
        , cy-2,
cx + 2, cy+2));
        canvas.drawPoint(
cx , cy, paint );
       
cx ++;
       
if ( cx > WIDTH )
        {
       
task .cancel();
       
task = null ;
        }
       
holder .unlockCanvasAndPost(canvas);
        }
        };
       
timer .schedule( task , 0,30);
        }
        });
        sin.setOnClickListener(listener);
        cos.setOnClickListener(listener);
       
holder .addCallback( new Callback()
        {
       
@Override
       
public void surfaceChanged(SurfaceHolder holder
        ,
int format, int width, int height)
        {
        drawBack(holder);
        }
       
@Override
       
public void surfaceCreated( final SurfaceHolder myHolder)
        {}
       
@Override
       
public void surfaceDestroyed(SurfaceHolder holder)
        {
       
timer .cancel();
        }
        });
    }
private void drawBack(SurfaceHolder holder)
{
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.
WHITE );
Paint p =
new Paint();
p.setColor(Color.
BLACK );
p.setStrokeWidth(2);
canvas.drawLine(
X_OFFSET , centerY , WIDTH , centerY , p);
canvas.drawLine(
X_OFFSET , 40, X_OFFSET , HEIGHT , p);
holder.unlockCanvasAndPost(canvas);
holder.lockCanvas(
new Rect(0,0,0,0));
holder.unlockCanvasAndPost(canvas);
}
}
程序每次绘制正弦、余弦波上的当前点时,无须重绘整个画面,SurfaceHolder只要锁定当前绘制点的小范围即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值