Android中使用SurfaceView和Canvas来绘制动画

转载自:http://blog.csdn.net/gophers

其实每个View中都有Canvas可以用来绘制动画,只需要在这个View中重载onDraw()方法就可以,但是SurfaceView类是一个专门用来制动动画的类。

Canvas(中文叫做”画布”)就和HTML5中的canvas标签一样可以在一定区域内自由绘制图形。Canvas+SurfaceView制作的动画与View Animation和Property Animation这类动画比起来更加适合大量的集中播放的动画,比如游戏画面、相机的图像显示等。

因为SurfaceView通常会在另一个专门的线程中不断重绘界面,所以不像其他动画那样要在主线程(UI线程)中播放动画的同时还要消耗一定的流畅度用来响应用户输入。

在使用SurfaceView时需要注意下面这些要点:

1)每个SurfaceView都需要一个SurfaceHolder对象来处理这个SurfaceView的生命周期和获取这个SurfaceView的Canvas对象,可以通过调用SurfaceView的getHolder()方法来获取它的SurfaceHolder对象。

2)使用SurfaceView时一般是通过继承SurfaceView的方式来实现,可以顺便implements两个接口,分别是Runnable和SurfaceHolder.Callback。第二个接口需要重载三个函数,这三个函数就是SurfaceView的生命周期处理了,可以通过SurfaceHolder对象的addCallback()方法把实现好的Callback对象传进去。

3)在使用SurfaceView的Canvas时一定要记得加锁同步,因为不能让画布同时绘制多个图案,通过调用这个SurfaceView的SurfaceHolder对象的lockCanvas()就可以做到这一点。绘制完毕后在调用SurfaceHolder对象的unlockCanvasAndPost()方法就可以解锁并更新。

下面给出了一个用SurfaceView和Canvas绘制动画的例子,一般直接复制上就可以运行看到效果:

package com.example.canvastest;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

public class MainActivity extends Activity {
    /*
     * 这个类用来当测试的物件,会沿着方形路线持续移动
     */
    class GameObject {
        private float x;
        private float y;
        private Bitmap img;
        private Paint paint;

        public GameObject() {
            this.img = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
            this.x = 100;
            this.y = 100;
            this.paint = new Paint();
        }

        // 在SurfaceView加锁同步后传给自己的Canvas上绘制自己
        public void drawSelf(Canvas canvas) {
            canvas.drawBitmap(img, x, y, paint);
        }

        // 获取物件下一次要绘制的位置(这里是沿着一个边长为400的正方形不断运动的)
        public void getNextPos() {
            if (y == 100 && x != 500)
                x += 5;
            else if (x == 500 && y != 500)
                y += 5;
            else if (y == 500 && x != 100)
                x -= 5;
            else if (x == 100 && y != 100)
                y -= 5;
        }
    }

    /*
     * 这个类就是加工了SurfaceView之后的类,所有要运动的物件都最终放在这里进行绘制
     */
    class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
        private Thread thread; // SurfaceView通常需要自己单独的线程来播放动画
        private Canvas canvas;
        private SurfaceHolder surfaceHolder;

        private GameObject obj;

        public MySurfaceView(Context c) {
            super(c);
            this.surfaceHolder = this.getHolder();
            this.surfaceHolder.addCallback(this);
            this.obj = new GameObject();
        }

        @Override
        public void run() {
            while (true) {
                obj.getNextPos();
                canvas = this.surfaceHolder.lockCanvas(); // 通过lockCanvas加锁并得到該SurfaceView的画布
                canvas.drawColor(Color.BLACK);
                obj.drawSelf(canvas); // 把SurfaceView的画布传给物件,物件会用这个画布将自己绘制到上面的某个位置
                this.surfaceHolder.unlockCanvasAndPost(canvas); // 释放锁并提交画布进行重绘
                try {
                    Thread.sleep(10); // 这个就相当于帧频了,数值越小画面就越流畅
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder arg0) {
            Toast.makeText(getApplicationContext(), "SurfaceView已经销毁", Toast.LENGTH_LONG).show();
        }

        @Override
        public void surfaceCreated(SurfaceHolder arg0) {
            Toast.makeText(getApplicationContext(), "SurfaceView已经创建", Toast.LENGTH_LONG).show();
            this.thread = new Thread(this);
            this.thread.start();
        }

        @Override
        public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
            // 这里是SurfaceView发生变化的时候触发的部分
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MySurfaceView(getApplicationContext())); // 别忘了开始的时候载入我们加工好的的SurfaceView
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

转载自:http://blog.csdn.net/gophers

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值