web-dev-qa-db-ja.com

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に存在します。)

最初の質問は、新しいレイアウトのwholeキャンバスをクリア(または再描画)するにはどうすればよいですか?
次に、画面の一部だけを更新するにはどうすればよいですか?

// 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);  }   }   }       }
86
samClem

新しいレイアウトの全キャンバスをクリア(または再描画)するにはどうすればよいですか(=ゲームで試してください)?

Canvas.drawColor(Color.BLACK) 、またはCanvasでクリアしたい色を呼び出すだけです。

そして:画面の一部だけを更新するにはどうすればよいですか?

Android OSは画面の更新時にすべてのピクセルを再描画するため、「画面の一部」を更新するだけの方法はありません。しかし、Canvasの古い図面をクリアしていない場合、古い図面はまだ表面にあり、それはおそらく画面の「一部だけを更新する」方法の1つです。

したがって、「画面の一部を更新する」場合は、Canvas.drawColor()メソッドを呼び出さないようにします。

71
Wroclai

PorterDuffのクリアモードで透明色を描画すると、私が望んでいたもののトリックができます。

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

これをグーグルグループで見つけて、これは私のために働いた..

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

これにより、設定されたビットマップを維持しながら、図面の長方形などが削除されます。

29
Rukmal Dias

私は@mobistryの答えを試しました:

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

しかし、私にはうまくいきませんでした。

私にとっての解決策は次のとおりです。

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

たぶん同じ問題を抱えている人もいます。

18
Derzu

pathクラスのresetメソッドを使用します

Path.reset();
14
Rakesh
mBitmap.eraseColor(Color.TRANSPARENT);

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

以下のコードを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" />

上記のコードを試してください...

私にとってCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)または同様の呼び出しは、画面に触れた後にのみ機能します。 SO上記のコード行を呼び出しますが、画面に触れると画面がクリアされます。だから私のために働いたのは、ビューを初期化するために作成時に呼び出される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();
}
3
Jason Crosby
canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);
3
aliakbarian

以下は、各フレームでCanvasのすべてのピクセルを常に再描画する必要があることを示す最小限の例のコードです。

このアクティビティは、前に画面をクリアせずに、SurfaceViewに新しいビットマップを毎秒描画します。テストすると、ビットマップが常に同じバッファーに書き込まれるわけではなく、画面が2つのバッファー間で交互に表示されることがわかります。

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

Invalidate()を呼び出すことを忘れないでください。

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

次のアプローチを使用すると、キャンバス全体またはその一部のみをクリアできます。
PorterDuff.Mode.CLEARはハードウェアアクセラレーションでは動作しないため、ハードウェアアクセラレーションを無効にすることを忘れないでください。onDrawメソッドをオーバーライドするため、最後にsetWillNotDraw(false)を呼び出します。

//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); 
0
ucMedia