Android,画布:如何清除(删除内容)位于 SurfaceView 中的画布(= 位图)?
为了制作一个简单的游戏,我使用了一个模板来绘制带有位图的画布,如下所示:(
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); } } } }
In order to make a simple game, I used a template that draws a canvas with bitmaps like this:
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); } }
(The canvas is defined in "run()" / the SurfaceView lives in a GameThread.)
My first question is how do I clear (or redraw) the whole canvas for a new layout?
Second, how can I update just a part of the screen?
// 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); } } } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(22)
使用 PorterDuff 清晰模式绘制透明颜色可以满足我的需求。
Draw transparent color with PorterDuff clear mode does the trick for what I wanted.
只需调用
Canvas.drawColor(Color.BLACK)
< /a> 或任何您想要用来清除Canvas
的颜色。不存在只更新“屏幕的一部分”的方法,因为 Android 操作系统在更新屏幕时会重绘每个像素。但是,当您不清除
Canvas
上的旧绘图时,旧绘图仍然在表面上,这可能是“仅更新屏幕的一部分”的一种方法。因此,如果您想“更新屏幕的一部分”,只需避免调用 Canvas.drawColor() 方法即可。
Just call
Canvas.drawColor(Color.BLACK)
, or whatever color you want to clear yourCanvas
with.There is no such method that just update a "part of the screen" since Android OS is redrawing every pixel when updating the screen. But, when you're not clearing old drawings on your
Canvas
, the old drawings are still on the surface and that is probably one way to "update just a part" of the screen.So, if you want to "update a part of the screen", just avoid calling
Canvas.drawColor()
method.在谷歌组中找到了这个,这对我有用。
这会删除绘图矩形等,同时保持设置的位图。
Found this in google groups and this worked for me..
This removes drawings rectangles etc. while keeping set bitmap..
使用Path类的reset方法
use the reset method of Path class
我尝试了@mobistry的答案:
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
但它对我不起作用。
对我来说,解决方案是:
canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);
也许有人有同样的问题。
I tried the answer of @mobistry:
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
But it doesn't worked for me.
The solution, for me, was:
canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);
Maybe some one has the same problem.
请将下面的代码粘贴到surfaceview扩展类构造函数上......
构造函数编码
xml编码
尝试上面的代码......
please paste below code on surfaceview extend class constructor.............
constructor coding
xml coding
try above code...
下面是一个最小示例的代码,显示您始终必须在每一帧重绘画布的每个像素。
此活动每秒在 SurfaceView 上绘制一个新的位图,之前不会清除屏幕。
如果您测试它,您会发现位图并不总是写入同一个缓冲区,并且屏幕将在两个缓冲区之间交替。
我在手机(Nexus S、Android 2.3.3)和模拟器(Android 2.2)上进行了测试。
Here is the code of a minimal example showing that you always have to redraw every pixel of the Canvas at each frame.
This activity draw a new Bitmap every second on the SurfaceView, without clearing the screen before.
If you test it, you will see that the bitmap is not always written to the same buffer, and the screen will alternate between the two buffers.
I tested it on my phone (Nexus S, Android 2.3.3), and on the emulator (Android 2.2).
对我来说,调用
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
或类似的操作只有在触摸屏幕后才会起作用。所以我会调用上面的代码行,但只有在触摸屏幕后屏幕才会清除。因此,对我有用的是调用invalidate()
,然后调用init()
,它在创建时调用以初始化视图。For me calling
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
or something similar would only work after I touch the screen. SO I would call the above line of code but the screen would only clear after I then touched the screen. So what worked for me was to callinvalidate()
followed byinit()
which is called at the time of creation to initialize the view.在 java android 中擦除 Canvas 与通过 javascript 使用 globalCompositeOperation 擦除 HTML Canvas 类似。逻辑是相似的。
U将选择DST_OUT(目的地输出)逻辑。
注意:DST_OUT 更有用,因为如果油漆颜色具有 50% alpha,它可以擦除 50%。因此,要完全清除到透明,颜色的 alpha 必须为 100%。建议使用paint.setColor(Color.WHITE)。并确保画布图像格式为RGBA_8888。
擦除后,用SRC_OVER(Source Over)返回正常绘图。
更新小区域显示实际上需要访问图形硬件,并且可能不支持。
最接近最高性能的是使用多图像层。
Erasing on Canvas in java android is similar erasing HTML Canvas via javascript with globalCompositeOperation. The logic was similar.
U will choose DST_OUT (Destination Out) logic.
Note: DST_OUT is more useful because it can erase 50% if the paint color have 50% alpha. So, to clear completely to transparent, the alpha of color must be 100%. Apply paint.setColor(Color.WHITE) is recommended. And make sure that the canvas image format was RGBA_8888.
After erased, go back to normal drawing with SRC_OVER (Source Over).
Update small area display literally will need to access graphic hardware, and it maybe not supported.
The most close for highest performance is using multi image layer.
我找到了我的解决方案。
PaintView 类:
和 MainActivity:
I found my solution.
PaintView class:
And MainActivity:
2023 年 11 月
通过以下方法,您可以清除整个画布或仅清除其中的一部分。
请不要忘记禁用硬件加速,因为 PorterDuff.Mode.CLEAR 不适用于硬件加速,并最终调用
setWillNotDraw(false)
因为我们覆盖了onDraw方法。
Nov 2023
With the following approach, you can clear the whole canvas or just a part of it.
Please do not forget to disable Hardware acceleration since PorterDuff.Mode.CLEAR doesn’t work with hardware acceleration and finally call
setWillNotDraw(false)
because we override theonDraw
method.不要忘记调用 invalidate();
Don't forget to call invalidate();
您的第一个要求,如何清除或重绘整个画布 - 答案 - 使用 canvas.drawColor(color.Black) 方法以黑色或您指定的任何颜色清除屏幕。
您的第二个要求,如何更新屏幕的一部分 - 答案 - 例如,如果您想在屏幕上保持所有其他内容不变,但在屏幕的一小块区域中显示一个整数(例如计数器),该整数每五秒后增加一次。然后使用 canvas.drawrect 方法通过指定左上右下并绘制来绘制该小区域。然后计算您的计数器值(使用 postdalayed 5 秒等,例如 Handler.postDelayed(Runnable_Object, 5000);) ,将其转换为文本字符串,计算这个小矩形中的 x 和 y 坐标并使用文本视图显示变化计数器值。
Your first requirement, how to clear or redraw whole canvas - Answer - use canvas.drawColor(color.Black) method for clearing the screen with a color of black or whatever you specify .
Your second requirement, how to update part of the screen - Answer - for example if you want to keep all other things unchanged on the screen but in a small area of screen to show an integer(say counter) which increases after every five seconds. then use canvas.drawrect method to draw that small area by specifying left top right bottom and paint. then compute your counter value(using postdalayed for 5 seconds etc., llike Handler.postDelayed(Runnable_Object, 5000);) , convert it to text string, compute the x and y coordinate in this small rect and use text view to display the changing counter value.
尝试在活动的 onPause() 处删除视图并添加 onRestart()
LayoutYouAddedYourView.addView(YourCustomView);
LayoutYouAddedYourView.removeView(YourCustomView);
当您添加视图时, onDraw() 方法将被调用。
YourCustomView 是一个扩展 View 类的类。
Try to remove the view at onPause() of an activity and add onRestart()
LayoutYouAddedYourView.addView(YourCustomView);
LayoutYouAddedYourView.removeView(YourCustomView);
The moment you add your view, onDraw() method would get called.
YourCustomView, is a class which extends the View class.
就我而言,我将画布绘制为线性布局。
再次清理并重绘:
然后,我用新值调用该类:
这是 Lienzo 类:
In my case, I draw my canvas into linearlayout.
To clean and redraw again:
and then, I call the class with the new values:
This is the class Lienzo:
就我而言,每次创建画布都对我有用,尽管它不利于记忆
In my case, creating canvas every time worked for me, even though it's not memory-friendly
以下对我有用:
The following worked for me:
也许是因为新的 Android Studio 版本,我实际上将这三个一起使用才最终使其工作:
它们都没有单独工作,花了我相当多的时间来测试......
Maybe it's because of the new Android Studio version, I actually used all three together to finally make it work :
None of them alone worked, spent me quite some time to test...
我必须使用单独的绘图通道来清除画布(锁定、绘制和解锁):
I had to use a separate drawing pass to clear the canvas (lock, draw and unlock):
只需调用
canvas.drawColor(Color.TRANSPARENT)
Just call
canvas.drawColor(Color.TRANSPARENT)