Android SurfaceView使用dirty rect刷新

Android SurfaceView使用dirty rect刷新_第1张图片

如上图,绘制一个背景图,一个不停旋转的小球

/**
 * author : stone
 * email  : [email protected]
 * time   : 15/12/15 01 08
 * 在一张大图中绘制一个小图,并旋转它
 */
public class MySurfaceView1 extends SurfaceView implements SurfaceHolder.Callback {

    private Bitmap mBack;
    private Bitmap mBall;
    private SurfaceHolder mHolder;
    private boolean mIsRun;

    public MySurfaceView1(Context context) {
        super(context);
        mBack = BitmapFactory.decodeResource(getResources(), R.drawable.back);
        mBall = BitmapFactory.decodeResource(getResources(), R.drawable.ball);
        mHolder = this.getHolder();// 获取holder
        mHolder.addCallback(this);
        mIsRun = true;
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 启动自定义线程
        new Thread(new MyRunn()).start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        this.mIsRun = false;
    }

    class MyRunn implements Runnable {

        @Override
        public void run() {
            Canvas canvas = null;
            int rotate = 0;// 旋转角度变量
            while (mIsRun) {
                try {
                    canvas = mHolder.lockCanvas();// 获取画布
                    //测试在中心绘圆
//                    Paint paint = new Paint();
//                    paint.setColor(Color.RED);
//                    canvas.drawCircle(mBack.getWidth() / 2, mBack.getHeight() / 2, 10, paint);

                    //绘制背景
                    canvas.drawBitmap(mBack, 0, 0, null);
                    // 创建矩阵以控制图片旋转和平移
                    Matrix m = new Matrix();
                    // 设置旋转角度
                    m.postRotate((rotate += 30) % 360, mBall.getWidth() / 2, mBall.getHeight() / 2);
                    // 设置左边距和上边距
                    m.postTranslate((mBack.getWidth() - mBall.getWidth()) / 2,
                            (mBack.getHeight() - mBall.getHeight()) / 2);
                    // 绘制ball
                    canvas.drawBitmap(mBall, m, null);
                    // 休眠以控制最大帧频为每秒约30帧
                    Thread.sleep(33);
                } catch (Exception e) {

                } finally {
                    try {
                        if (mIsRun) {
                            mHolder.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }
        }

    }
}
如上代码,每帧都会 重绘一次背景和小球图。

但实际上,我只想要小球图一直在动,即被重绘;而背景图不要一直重绘。

那么就可以用surfaceview.lockCanvas(Rect dirty),只重绘该rect区域内即可

如下

    // 自定义线程类
    class MyRunn implements Runnable {

        @Override
        public void run() {
            Canvas canvas = null;
            int rotate = 0;// 旋转角度变量
            int frameCount = 0;
            while (true) {
                try {
                    int x = (mBack.getWidth() - mBall.getWidth()) / 2;
                    int y = (mBack.getHeight() - mBall.getHeight()) / 2;

                    // 获取画布
                    canvas = mHolder.lockCanvas(new Rect(x, y, x + mBall.getWidth(),y + mBall.getHeight()));
                    //测试在中心绘圆
//                    Paint paint = new Paint();
//                    paint.setColor(Color.RED);
//                    canvas.drawCircle(mBack.getWidth() / 2, mBack.getHeight() / 2, 10, paint);

                    //绘制背景一次
                    if (frameCount < 1) {
                        canvas.drawBitmap(mBack, 0, 0, null);
                        frameCount++;
                    }
                    //创建矩阵以控制图片旋转和平移
                    Matrix m = new Matrix();
                    // 设置旋转角度
                    m.postRotate((rotate += 30) % 360, mBall.getWidth() / 2, mBall.getHeight() / 2);
                    // 设置左边距和上边距
                    m.postTranslate(x, y) ;
                    // 绘制ball
                    canvas.drawBitmap(mBall, m, null);
                    // 休眠以控制最大帧频为每秒约30帧
                    Thread.sleep(33);
                } catch (Exception e) {

                } finally {
                    if (mIsRun) {
                        mHolder.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像
                    }
                }
            }
        }

    }

只绘制一次背景,出现了闪烁的情况,如下图

Android SurfaceView使用dirty rect刷新_第2张图片

通过模拟器,和真机测试,发现,背景绘制次数在模拟器上低于3次,在小米手机上低于4次,会有这闪烁问题

这里我干脆改成五次:

if (frameCount < 5) {
    canvas.drawBitmap(mBack, 0, 0, null);
    frameCount++;
}



你可能感兴趣的:(Android,自定义view)