105

为了制作一个简单的游戏,我使用了一个模板,该模板使用这样的位图绘制画布:

private void doDraw(Canvas canvas) {
    for (int i=0;i<8;i++)
        for (int j=0;j<9;j++)
            for (int k=0;k<7;k++)   {
    canvas.drawBitmap(mBits[allBits[i][j][k]], i*50 -k*7, j*50 -k*7, null); } }

(画布在“run()”中定义/SurfaceView 位于 GameThread 中。)

我的第一个问题是如何清除(或重绘)整个画布以进行新布局?
其次,我怎样才能只更新屏幕的一部分?

// This is the routine that calls "doDraw":
public void run() {
    while (mRun) {
        Canvas c = null;
        try {
            c = mSurfaceHolder.lockCanvas(null);
            synchronized (mSurfaceHolder) {
                if (mMode == STATE_RUNNING) 
                    updateGame();
                doDraw(c);          }
        } finally {
            if (c != null) {
                mSurfaceHolder.unlockCanvasAndPost(c);  }   }   }       }
4

21 回答 21

288

使用 PorterDuff 清除模式绘制透明颜色可以达到我想要的效果。

Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
于 2012-06-04T13:37:35.673 回答
83

如何清除(或重绘)整个画布以获得新布局(= 尝试游戏)?

只需调用Canvas.drawColor(Color.BLACK),或任何您想要清除的颜色Canvas

并且:我怎样才能只更新屏幕的一部分?

没有这种方法可以只更新“屏幕的一部分”,因为 Android 操作系统在更新屏幕时会重绘每个像素。但是,当您不清除 上Canvas的旧图纸时,旧图纸仍然在表面上,这可能是“仅更新一部分”屏幕的一种方式。

因此,如果您想“更新屏幕的一部分”,请避免调用Canvas.drawColor()方法。

于 2011-04-20T12:01:33.863 回答
35

在谷歌群组中找到了这个,这对我有用..

Paint clearPaint = new Paint();
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(0, 0, width, height, clearPaint); 

这将删除绘图矩形等,同时保持设置位图..

于 2012-09-04T12:13:42.577 回答
21

使用 Path 类的 reset 方法

Path.reset();
于 2013-11-06T12:22:27.033 回答
18

我尝试了@mobistry 的答案:

canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);

但这对我不起作用。

对我来说,解决方案是:

canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);

也许有人有同样的问题。

于 2014-05-21T04:47:21.897 回答
12
mBitmap.eraseColor(Color.TRANSPARENT);

canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
于 2012-11-02T13:27:17.737 回答
5
canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);
于 2017-03-05T07:38:25.717 回答
4

请在surfaceview扩展类构造函数上粘贴下面的代码............

构造函数编码

    SurfaceHolder holder = getHolder();
    holder.addCallback(this);

    SurfaceView sur = (SurfaceView)findViewById(R.id.surfaceview);
    sur.setZOrderOnTop(true);    // necessary
    holder = sur.getHolder();
    holder.setFormat(PixelFormat.TRANSPARENT);

xml编码

    <com.welcome.panelview.PanelViewWelcomeScreen
        android:id="@+id/one"
        android:layout_width="600px"
        android:layout_height="312px"
        android:layout_gravity="center"
        android:layout_marginTop="10px"
        android:background="@drawable/welcome" />

试试上面的代码...

于 2012-06-22T07:25:37.070 回答
3

这是一个最小示例的代码,显示您总是必须在每一帧重绘 Canvas 的每个像素。

这个活动每秒在 SurfaceView 上绘制一个新的 Bitmap,之前没有清屏。如果你测试一下,你会发现位图并不总是写入同一个缓冲区,屏幕会在两个缓冲区之间交替显示。

我在我的手机(Nexus S,Android 2.3.3)和模拟器(Android 2.2)上测试了它。

public class TestCanvas extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new TestView(this));
    }
}

class TestView extends SurfaceView implements SurfaceHolder.Callback {

    private TestThread mThread;
    private int mWidth;
    private int mHeight;
    private Bitmap mBitmap;
    private SurfaceHolder mSurfaceHolder;

    public TestView(Context context) {
        super(context);
        mThread = new TestThread();
        mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon);
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        mWidth = width;
        mHeight = height;
        mThread.start();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {/* Do nothing */}

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mThread != null && mThread.isAlive())
            mThread.interrupt();
    }

    class TestThread extends Thread {
        @Override
        public void run() {
            while (!isInterrupted()) {
                Canvas c = null;
                try {
                    c = mSurfaceHolder.lockCanvas(null);
                    synchronized (mSurfaceHolder) {
                        c.drawBitmap(mBitmap, (int) (Math.random() * mWidth), (int) (Math.random() * mHeight), null);
                    }
                } finally {
                    if (c != null)
                        mSurfaceHolder.unlockCanvasAndPost(c);
                }

                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    interrupt();
                }
            }
        }   
    }
}
于 2011-04-20T13:26:04.663 回答
3

对我来说,打电话Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)或类似的事情只有在我触摸屏幕后才会起作用。所以我会调用上面的代码行,但只有在我触摸屏幕后屏幕才会清除。所以对我有用invalidate()的是调用,然后init()在创建时调用哪个来初始化视图。

private void init() {
    setFocusable(true);
    setFocusableInTouchMode(true);
    setOnTouchListener(this);

    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(Color.BLACK);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(6);

    mCanvas = new Canvas();
    mPaths = new LinkedList<>();

    addNewPath();
}
于 2015-08-30T19:15:58.853 回答
2

在 java android 中擦除 Canvas 类似于通过 javascript 使用 globalCompositeOperation 擦除 HTML Canvas。逻辑是相似的。

U 将选择 DST_OUT(目的地输出)逻辑。

paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));

注意:DST_OUT 更有用,因为如果油漆颜色有 50% 的 alpha,它可以擦除 50%。因此,要完全清除到透明,颜色的 alpha 必须为 100%。建议应用paint.setColor(Color.WHITE)。并确保画布图像格式为 RGBA_8888。

擦除后,使用 SRC_OVER (Source Over) 回到正常绘图。

paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));

从字面上更新小区域显示将需要访问图形硬件,并且可能不受支持。

最接近最高性能的是使用多图像层。

于 2020-06-14T10:02:56.517 回答
1

不要忘记调用 invalidate();

canvas.drawColor(backgroundColor);
invalidate();
path.reset();
于 2019-08-17T16:28:40.147 回答
1

使用以下方法,您可以清除整个画布或只是其中的一部分。
请不要忘记禁用硬件加速,因为PorterDuff.Mode.CLEAR不适用于硬件加速并最终调用setWillNotDraw(false),因为我们覆盖了该onDraw方法。

//view's constructor
setWillNotDraw(false);
setLayerType(LAYER_TYPE_SOFTWARE, null);

//view's onDraw
Paint TransparentPaint = new Paint();
TransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(0, 0, width, height, TransparentPaint); 
于 2019-08-22T13:08:59.037 回答
0

以下对我有用:

canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SCREEN);
于 2021-12-17T23:34:11.200 回答
0

尝试在活动的 onPause() 删除视图并添加 onRestart()

LayoutYouAddedYourView.addView(YourCustomView); LayoutYouAddedYourView.removeView(YourCustomView);

添加视图的那一刻,将调用 onDraw() 方法。

YourCustomView,是一个扩展 View 类的类。

于 2019-10-17T07:17:53.347 回答
0

就我而言,每次创建画布都对我有用,即使它对内存不友好

Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.image);
imageBitmap = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), bm.getConfig());
canvas = new Canvas(imageBitmap);
canvas.drawBitmap(bm, 0, 0, null);
于 2021-02-15T15:43:40.390 回答
0

In my case, I draw my canvas into linearlayout. To clean and redraw again:

    LinearLayout linearLayout = findViewById(R.id.myCanvas);
    linearLayout.removeAllViews();

and then, I call the class with the new values:

    Lienzo fondo = new Lienzo(this,items);
    linearLayout.addView(fondo);

This is the class Lienzo:

class Lienzo extends View {
    Paint paint;
    RectF contenedor;
    Path path;
    ArrayList<Items>elementos;

    public Lienzo(Context context,ArrayList<Items> elementos) {
        super(context);
        this.elementos=elementos;
        init();
    }

    private void init() {
        path=new Path();
        paint = new Paint();
        contenedor = new RectF();
        paint.setStyle(Paint.Style.FILL);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        contenedor.left = oneValue;
        contenedor.top = anotherValue;
        contenedor.right = anotherValue;
        contenedor.bottom = anotherValue;

        float angulo = -90; //starts drawing at 12 o'clock
        //total= sum of all element values
        for (int i=0;i<elementos.size();i++){
            if (elementos.get(i).angulo!=0 && elementos.get(i).visible){
                paint.setColor(elementos.get(i).backColor);
                canvas.drawArc(contenedor,angulo,(float)(elementos.get(i).value*360)/total,true,paint);

                angulo+=(float)(elementos.get(i).value*360)/total;
            }
        } //for example
    }
}
于 2020-07-24T18:24:13.453 回答
0

我找到了我的解决方案。

油漆视图类:

public void clear() {
    mPath.reset();
    mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    paths.clear();
}

和 MainActivity:

  clear_canvas_.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            paintView.clear();
        }
    });
于 2022-01-11T07:19:28.853 回答
-1

您的第一个要求,如何清除或重绘整个画布 - 答案 - 使用 canvas.drawColor(color.Black) 方法以黑色或您指定的任何颜色清除屏幕。

您的第二个要求,如何更新屏幕的一部分 - 回答 - 例如,如果您想在屏幕上保持所有其他内容不变,但在屏幕的一小块区域中显示一个整数(比如计数器),该整数在每五秒后增加一次。然后使用 canvas.drawrect 方法通过指定左上右下并绘制来绘制那个小区域。然后计算您的计数器值(使用 postdalayed 5 秒等,就像 Handler.postDelayed(Runnable_Object, 5000);) ,将其转换为文本字符串,计算这个小矩形中的 x 和 y 坐标并使用文本视图显示变化计数器值。

于 2013-04-08T01:28:11.013 回答
-1

我不得不使用单独的绘图通道来清除画布(锁定、绘制和解锁):

Canvas canvas = null;
try {
    canvas = holder.lockCanvas();
    if (canvas == null) {
        // exit drawing thread
        break;
    }
    canvas.drawColor(colorToClearFromCanvas, PorterDuff.Mode.CLEAR);
} finally {
    if (canvas != null) {
        holder.unlockCanvasAndPost(canvas);
    }
}
于 2018-08-12T18:51:53.947 回答
-3

打电话

canvas.drawColor(颜色。透明)

于 2011-11-29T09:20:20.100 回答