web-dev-qa-db-fra.com

Android, toile: Comment effacer (supprimer le contenu de) une toile (= bitmaps), vivant dans une surfaceView?

Afin de faire un jeu simple, j'ai utilisé un modèle qui dessine une toile avec des bitmaps comme ceci:

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

(Le canevas est défini dans "run ()"/la SurfaceView vit dans un GameThread.)

Ma première question est de savoir comment effacer (ou redessiner) le canevas entier pour une nouvelle mise en page?
Deuxièmement, comment puis-je mettre à jour une partie seulement de l'écran?

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

Comment effacer (ou redessiner) la toile ENTIÈRE pour une nouvelle mise en page (= essayer le jeu)?

Appelez simplement Canvas.drawColor(Color.BLACK) , ou la couleur de votre choix pour effacer votre Canvas avec.

Et: comment puis-je mettre à jour juste une partie de l'écran?

Aucune méthode de ce type ne met à jour une "partie de l'écran" depuis Android l'OS redessine chaque pixel lors de la mise à jour de l'écran. Toutefois, lorsque vous n'effacez pas d'anciens dessins sur votre Canvas, les anciens dessins sont toujours à la surface et c'est probablement un moyen de "mettre à jour une partie seulement" de l'écran.

Donc, si vous voulez "mettre à jour une partie de l'écran", évitez simplement d'appeler la méthode Canvas.drawColor().

71
Wroclai

Dessinez des couleurs transparentes avec le mode clair PorterDuff, faites ce que je voulais.

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

Trouvé cela dans les groupes de Google et cela a fonctionné pour moi ..

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

Cela supprime les rectangles de dessin, etc. tout en conservant la définition bitmap.

29
Rukmal Dias

J'ai essayé la réponse de @mobistry:

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

Mais ça n'a pas fonctionné pour moi.

La solution, pour moi, était la suivante:

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

Peut-être que quelqu'un a le même problème.

18
Derzu

utiliser la méthode reset de la classe Path

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

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

veuillez coller ci-dessous le code sur le constructeur de la classe d’extension surfaceview .............

codage constructeur

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

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

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

essayez le code ci-dessus ...

4

Pour moi, appeler Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR) ou quelque chose de similaire ne fonctionnerait que lorsque je toucherais l'écran. SO J'appellerais la ligne de code ci-dessus, mais l'écran ne s'effacerait qu'après avoir touché l'écran. Ce qui a bien fonctionné pour moi a donc été d'appeler invalidate() suivi de init() qui est appelé au moment de la création pour initialiser la vue.

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

Voici le code d'un exemple minimal montrant qu'il faut toujours redessiner chaque pixel du canevas à chaque image.

Cette activité dessine un nouveau bitmap toutes les secondes sur le SurfaceView, sans vider l’écran auparavant. Si vous le testez, vous verrez que le bitmap n'est pas toujours écrit dans le même tampon, et l'écran alterne entre les deux tampons.

Je l'ai testé sur mon téléphone (Nexus S, Android 2.3.3) et sur l'émulateur (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
Guillaume Brunerie

N'oubliez pas d'appeler invalidate ();

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

Avec l'approche suivante, vous pouvez effacer la totalité ou une partie de la toile.
N'oubliez pas de désactiver l'accélération matérielle car PorterDuff.Mode.CLEAR ne fonctionne pas avec l'accélération matérielle et appelle enfin setWillNotDraw(false), car nous remplaçons le onDraw méthode.

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