2012-08-07 20 views
15

Voglio dipingere la grafica su una tela in modo tale che i colori siano additivi. Per esempio, io voglio produrre questo:
Proper additive colorsCome dipingere con alfa?

Ma invece, ottengo questo:
My results

Si noti che il mezzo bianco, sfondo metà nero è intenzionale, solo per vedere come alfa interagisce sia con sfondi. Sarò felice di avere questo lavoro con entrambi i precedenti. Ecco il mio codice:

public class VennColorsActivity extends Activity { 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     class VennView extends View { 
      public VennView(Context context) { 
       super(context); 
      } 

      @Override 
      protected void onDraw(Canvas canvas) { 
       super.onDraw(canvas); 
       int alpha = 60, val = 255; 
       int ar = Color.argb(alpha, val, 0, 0); 
       int ag = Color.argb(alpha, 0, val, 0); 
       int ab = Color.argb(alpha, 0, 0, val); 
       float w = canvas.getWidth(); 
       float h = canvas.getHeight(); 
       float cx = w/2f; 
       float cy = h/2; 
       float r = w/5; 
       float tx = (float) (r * Math.cos(30 * Math.PI/180)); 
       float ty = (float) (r * Math.sin(30 * Math.PI/180)); 
       float expand = 1.5f; 
       Paint paint = new Paint(); 
       paint.setColor(Color.WHITE); 
       canvas.drawRect(new Rect(0, 0, (int) w, (int) (h/2)), paint); 
       PorterDuff.Mode mode = android.graphics.PorterDuff.Mode.ADD; 
       paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
       paint.setColorFilter(new PorterDuffColorFilter(ar, mode)); 
       paint.setColor(ar); 
       canvas.drawCircle(cx, cy - r, expand * r, paint); 
       paint.setColorFilter(new PorterDuffColorFilter(ag, mode)); 
       paint.setColor(ag); 
       canvas.drawCircle(cx - tx, cy + ty, expand * r, paint); 
       paint.setColorFilter(new PorterDuffColorFilter(ab, mode)); 
       paint.setColor(ab); 
       canvas.drawCircle(cx + tx, cy + ty, expand * r, paint); 
      } 
     } 
     this.setContentView(new VennView(this)); 
    } 
} 

Qualcuno può aiutarmi a capire come dipingere con colori additivi nella grafica Android?

risposta

26

Sei sulla strada giusta. Ci sono 3 principali problemi nel codice:

  • È necessario impostare xfer modalità filtro colore iso
  • Utilizzo temporaneo bitmap per rendere la vostra immagine
  • Alpha dovrebbe essere 0xFF al fine di ottenere i risultati che stai cercando

Ecco cosa ho ottenuto utilizzando la modalità xfer. Quello che sto facendo è il disegno di tutto in bitmap temporanea e quindi il rendering dell'intera bitmap sulla tela principale.

xfer mode rules

Mi chiedi perché avete bisogno di temperatura bitmap? Buona domanda! Se si sta disegnando tutto su una tela principale, i colori saranno mescolati con il colore di sfondo della tela principale, quindi tutti i colori verranno incasinati. La bitmap temporanea trasparente aiuta a mantenere i colori lontani da altre parti dell'interfaccia utente

Assicurati di non allocare nulla in onDraw() - la memoria si esaurirà molto presto in questo modo .. Assicurati inoltre di aver riciclato la bitmap temporanea quando non ne hai più bisogno.

package com.example.stack2; 

import android.app.Activity; 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.Bitmap.Config; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.PorterDuff.Mode; 
import android.graphics.PorterDuffXfermode; 
import android.os.Bundle; 
import android.view.View; 

public class YouAreWelcome extends Activity { 

    Bitmap tempBmp = Bitmap.createBitmap(1, 1, Config.ARGB_8888); 
    Canvas c = new Canvas(); 
    Paint paint = new Paint(); 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     class VennView extends View { 
      public VennView(Context context) { 
       super(context); 

      } 

      protected void onDraw(Canvas canvas) { 
       super.onDraw(canvas); 
       if(tempBmp.isRecycled() || tempBmp.getWidth()!=canvas.getWidth() || tempBmp.getHeight()!=canvas.getHeight()) 
       { 
        tempBmp.recycle(); 
        tempBmp = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888); 
        c.setBitmap(tempBmp); 
       } 

        //clear previous drawings 
       c.drawColor(Color.TRANSPARENT, Mode.CLEAR); 

       int alpha = 255, val = 255; 
       int ar = Color.argb(alpha, val, 0, 0); 
       int ag = Color.argb(alpha, 0, val, 0); 
       int ab = Color.argb(alpha, 0, 0, val); 
       float w = canvas.getWidth(); 
       float h = canvas.getHeight(); 
       float cx = w/2f; 
       float cy = h/2; 
       float r = w/5; 
       float tx = (float) (r * Math.cos(30 * Math.PI/180)); 
       float ty = (float) (r * Math.sin(30 * Math.PI/180)); 
       float expand = 1.5f; 
       paint.setAntiAlias(true); 
       paint.setXfermode(new PorterDuffXfermode(Mode.ADD)); 
       paint.setColor(ar); 
       c.drawCircle(cx, cy - r, expand * r, paint); 
       paint.setColor(ag); 
       c.drawCircle(cx - tx, cy + ty, expand * r, paint); 
       paint.setColor(ab); 
       c.drawCircle(cx + tx, cy + ty, expand * r, paint); 
       canvas.drawBitmap(tempBmp, 0, 0, null); 
      } 
     } 
     this.setContentView(new VennView(this)); 
    } 
} 
+1

Grazie mille, Pavel; e anche così veloce! –

+3

BTW, sapresti di un'alternativa a PorterDuff.Mode.ADD compatibile con SDK versione 8? La documentazione dice che ADD è stato aggiunto nella versione 8 ma si trova. È stato davvero introdotto nella versione 11 e si blocca su alcuni dispositivi meno recenti che non avrebbero dovuto essere autorizzati a installare il mio widget. –

+1

Questo è fantastico!Puoi applicare questa tecnica alle bitmap che si sovrappongono? –

2

Grazie ancora Pavel. Sarebbe stato molto difficile per me aver capito da solo. Sto rispondendo alla mia domanda per approfondire i dettagli, ma ho accettato la tua come migliore risposta.

Hai ragione che preferisco non dover creare e gestire un Bitmap fuori schermo (e Canvas). Questo è essenzialmente il motivo per cui ho detto che uno sfondo bianco o nero andrebbe bene per fare questo lavoro.

Non mi preoccupo mai delle prestazioni prima di vedere qualcosa funzionare, ma condivido la vostra attenzione dopo quel punto. La modifica della versione per ripararla e rimuovere tali membri fornisce l'implementazione di seguito.

È affidabile? Notare le due chiamate a Canvas.drawColor() che sospetto potrebbero anche essere combinate in una sola.

package com.superliminal.android.test.venn; 

import android.app.Activity; 
import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.PorterDuff.Mode; 
import android.graphics.PorterDuffXfermode; 
import android.os.Bundle; 
import android.view.View; 

public class VennColorsActivity extends Activity { 
    private Paint paint = new Paint(); 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     class VennView extends View { 
      public VennView(Context context) { 
       super(context); 
      } 

      @Override 
      protected void onDraw(Canvas canvas) { 
       super.onDraw(canvas); 
       canvas.drawColor(Color.BLACK); 
       canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR); 
       int alpha = 255, val = 255; 
       int ar = Color.argb(alpha, val, 0, 0); 
       int ag = Color.argb(alpha, 0, val, 0); 
       int ab = Color.argb(alpha, 0, 0, val); 
       float w = canvas.getWidth(); 
       float h = canvas.getHeight(); 
       float cx = w/2f; 
       float cy = h/2; 
       float r = w/5; 
       float tx = (float) (r * Math.cos(30 * Math.PI/180)); 
       float ty = (float) (r * Math.sin(30 * Math.PI/180)); 
       float expand = 1.5f; 
       paint.setAntiAlias(true); 
       paint.setXfermode(new PorterDuffXfermode(Mode.ADD)); 
       paint.setColor(ar); 
       canvas.drawCircle(cx, cy - r, expand * r, paint); 
       paint.setColor(ag); 
       canvas.drawCircle(cx - tx, cy + ty, expand * r, paint); 
       paint.setColor(ab); 
       canvas.drawCircle(cx + tx, cy + ty, expand * r, paint); 
      } 
     } 
     setContentView(new VennView(this)); 
    } 
} 
+1

anche questa soluzione è corretta. Ho suggerito di utilizzare una bitmap separata perché di solito si desidera unire solo i colori che si desidera e non rovinare il resto dell'interfaccia utente. L'unico commento al tuo codice è che 'canvas.drawColor (Color.BLACK);' la chiamata è inutile poiché si cancella l'intera area chiamando 'canvas.drawColor (Color.TRANSPARENT, Mode.CLEAR);'. Quindi in teoria puoi rilasciare questa riga –

+0

@Melinda Green come posso cambiare il colore della tela su ogni clic del pulsante nella mia attività in modo che possa dare diversi colori di sfondo – Erum

+0

@Erum Hannan Basta memorizzare un colore nel metodo onClick del pulsante e impostare quel colore come sfondo con canvas.drawColor con esso in onDraw. –