SurfaceView.lockCanvas()无法正确清除位图缓冲区

时间:2012-08-10 23:56:32

标签: android surfaceview clear

我创建了一个扩展SurfaceView的类,以便循环一系列ARGB位图。 除了为每个新帧保留(通常但不总是)基础位图的状态之外,这大部分都有效。

换句话说,如果我显示的第一帧是不透明的,后续帧是透明的,那么在绘制新帧时不会清除原始帧中的不透明像素。

这种行为让我感到困惑,因为SurfaceHolder.lockCanvas()的文档特别指出:

“在libeCanvas()和lockCanvas()之间永远不会保留Surface的内容,因此,必须写入Surface区域中的每个像素。”

如果我有一个坚实的背景,那么调用canvas.drawARGB(255,0,0,0)成功将其清除为黑色...但我希望有一个透明的背景,我无法清除它到透明色,因为canvas.drawARGB(0,0,0,0)没有效果。

import java.util.ArrayList;
import java.util.Random;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/*
 * Accepts a sequence of Bitmap buffers and cycles through them.
 */

class AnimatedBufferView extends SurfaceView implements Runnable
{
    Thread thread = null;
    SurfaceHolder surfaceHolder;
    volatile boolean running = false;

    ArrayList<Bitmap> frames;
    int curIndex = 0;

    public AnimatedBufferView(ArrayList<Bitmap> _frames, Context context) 
    {
        super(context);
        surfaceHolder = getHolder();
        frames = _frames;
    }

    public void onResume(){
        running = true;
        thread = new Thread(this);
        thread.start();
    }

    public void onPause(){
        boolean retry = true;
        running = false;
        while(retry){
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    @Override
    public void run() 
    {
        // TODO Auto-generated method stub
        while(running)
        {
            if(surfaceHolder.getSurface().isValid())
            {               
                Canvas canvas = surfaceHolder.lockCanvas();

                //clear the buffer?
                //canvas.drawARGB(255, 0, 0, 0);

                //display the saved frame-buffer..
                Matrix identity = new Matrix();
                Bitmap frame = frames.get(curIndex);
                canvas.drawBitmap(frame, identity, null);


                surfaceHolder.unlockCanvasAndPost(canvas);

                curIndex = (curIndex + 1) % frames.size();

                try {
                    thread.sleep( 100 );
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

3 个答案:

答案 0 :(得分:5)

好的,发现问题是默认的Porter-Duff绘图模式,这使得无法绘制透明颜色。只需改变模式。即,

Canvas canvas surfaceView.lockCanvas();
canvas.drawColor(0, Mode.CLEAR);

答案 1 :(得分:1)

这个让我困惑了一段时间。基本上,您将不得不每帧重绘整个屏幕。这是因为当你锁定画布时,你得到的是一个后面两帧的画布,而不是发布的最后一帧。这是由于帧的缓冲方式。只有两个缓冲区,当前正在显示的缓冲区,以及在当前缓冲区之前发布的缓冲区。当您锁定画布时,您将获得当前未显示的画布(这意味着您将获得一个后面的画布)。

这就是为什么你可能会听到人们将缓冲区称为交换缓冲区,因为当前显示屏幕与你绘制所有内容的屏幕交换。这意味着你永远不会真正找回最新的缓冲区。

希望对你有所帮助。

答案 2 :(得分:0)

google doc说正确的事情......因为你重新锁定表面的像素并且有两个缓冲区,因为android使用tripple或double缓存,具体取决于绘图调用的速度,它可以在一帧上绘制一个缓冲区无论你在之前和之后的绘图调用中填充了什么内容,它都可以使用另一个内容绘制另一个缓冲区,这样你就可以锁定由另一个缓冲区组成的数据表面....

所以更好地覆盖所有内容,然后再绘制像你所说的那样,例如使用proter duff模式和清晰的颜色,或只是使用canvas.drawColor(Color.BLACK);

的黑色颜色