IT story

Android, 캔버스 : surfaceView에있는 캔버스 (= 비트 맵)를 지우는 (내용을 삭제) 어떻게합니까?

hot-time 2020. 9. 12. 11:30
반응형

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);  }   }   }       }

새 레이아웃을 위해 전체 캔버스를 지우거나 다시 그리려면 어떻게합니까 (= 게임에서 시도)?

을 호출 Canvas.drawColor(Color.BLACK)하거나 지우고 싶은 색상을 선택하세요 Canvas.

그리고 : 화면의 일부만 업데이트하려면 어떻게해야합니까?

Android OS는 화면을 업데이트 할 때 모든 픽셀을 다시 그리기 때문에 "화면의 일부"만 업데이트하는 방법은 없습니다. 그러나에서 이전 그림을 지우지 않을 때 Canvas이전 그림이 여전히 표면에 남아 있으며 이는 아마도 화면의 "일부만 업데이트"하는 한 가지 방법 일 것입니다.

따라서 "화면의 일부를 업데이트"하려면 Canvas.drawColor()메서드 호출을 피하십시오 .


PorterDuff 클리어 모드로 투명한 색상을 그립니다.

Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)

Google 그룹에서 이걸 찾았고이게 저에게 효과적이었습니다 ..

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

설정된 비트 맵을 유지하면서 도면 직사각형 등을 제거합니다.


@mobistry의 답변을 시도했습니다.

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

그러나 그것은 나를 위해 일하지 않았습니다.

저에게 해결책은 다음과 같습니다.

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

어쩌면 어떤 사람은 같은 문제를 가지고있을 것입니다.


경로 클래스의 재설정 방법 사용

Path.reset();

mBitmap.eraseColor(Color.TRANSPARENT);

canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

please paste below code on surfaceview extend class constructor.............

constructor coding

    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 coding

    <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" />

try above code...


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).

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();
                }
            }
        }   
    }
}

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 call invalidate() followed by init() which is called at the time of creation to initialize the view.

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();
}

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

Don't forget to call invalidate();

canvas.drawColor(backgroundColor);
invalidate();
path.reset();

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 the onDraw method.

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

//view's onDraw
Paint TransparentPaint = new Paint();
TransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(0, 0, width, height, TransparentPaint); 

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.


I had to use a separate drawing pass to clear the canvas (lock, draw and unlock):

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);
    }
}

Just call

canvas.drawColor(Color.TRANSPARENT)

참고URL : https://stackoverflow.com/questions/5729377/android-canvas-how-do-i-clear-delete-contents-of-a-canvas-bitmaps-livin

반응형