2012-08-07 22 views
15

Chcę malować grafikę na płótnie tak, aby kolory były addytywne. Na przykład, chcę produkować to:
Proper additive colorsJak malować alfa?

Ale zamiast tego, mam to:
My results

Należy pamiętać, że pół białe, pół czarne tło jest zamierzone, żeby zobaczyć, jak alfa współdziała zarówno z tła. Będę szczęśliwy, że będę mógł pracować z dowolnym tłem. Oto mój kod:

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

Czy ktoś może mi pomóc zrozumieć, jak malować z dodatkowymi kolorami w grafice systemu Android?

Odpowiedz

26

Jesteś na dobrej drodze. Istnieją 3 główne problemy w kodzie:

  • Musisz ustawić xfer trybu filtr kolorów ISO
  • Zastosowanie temp bitmapę do renderowania obraz
  • Alpha powinny być 0xFF w celu uzyskania wyników, którego szukasz

Oto, co mam, korzystając z trybu xfer. Co robię - polega na wciągnięciu wszystkiego w tymczasową bitmapę, a następnie renderowaniu całej bitmapy do głównego płótna.

xfer mode rules

Pytasz dlaczego trzeba bitmapę temp? Dobre pytanie! Jeśli rysujesz wszystko na głównym płótnie, twoje kolory będą mieszane z głównym tłem tła, więc wszystkie kolory zostaną pomieszane. Przezroczysta mapa bitowa pomaga utrzymać kolory z dala od innych części UI Proszę się upewnić, że nic nie przydzielasz w onDraw() - wkrótce skończy Ci się pamięć w ten sposób. Upewnij się również, że zregenerowałeś swoją mapę bitową kiedy już go nie potrzebujesz.

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

Wielkie dzięki, Pavel; i tak szybko też! –

+3

BTW, czy znasz alternatywę dla PorterDuff.Mode.ADD, która jest kompatybilna z SDK w wersji 8? Dokumentacja mówi, że ADD dodano w wersji 8, ale leży. Zostało to naprawdę wprowadzone w wersji 11 i zawiesza się na starszych urządzeniach, które nie powinny mieć zainstalowanego widżetu. –

+1

To jest świetne!Czy możesz zastosować tę technikę do map bitowych, które nakładają się na siebie? –

2

Jeszcze raz dziękuję Pavel. Byłoby mi bardzo trudno dojść do tego sam. Odpowiadam na własne pytanie, aby lepiej wyćwiczyć szczegóły, ale zaakceptowałem twoją jako najlepszą odpowiedź.

Masz rację, że wolę nie tworzyć i zarządzać poza-ekranową bitmapą (i płótnem). Zasadniczo dlatego wspomniałem, że czarne lub białe tło byłoby w porządku, aby to działało.

Nigdy nie przejmuję się wydajnością, zanim zobaczę, że coś działa, ale podzielam twoją ostrożność po tym punkcie. Edytowanie wersji w celu naprawienia i usunięcia tych elementów daje implementację poniżej.

Czy to jest mocne? Zauważ, że dwa wywołania funkcji Canvas.drawColor(), które podejrzewam, mogą być również połączone w jeden.

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

to rozwiązanie jest również poprawne. Zaproponowałem użycie oddzielnej bitmapy, ponieważ zazwyczaj chcesz mieszać tylko wybrane kolory i nie zepsuć się z resztą interfejsu użytkownika. Jedynym komentarzem do twojego kodu jest to, że 'canvas.drawColor (Color.BLACK);' call jest bezużyteczne, ponieważ wyczyścisz cały obszar, wywołując 'canvas.drawColor (Color.TRANSPARENT, Mode.CLEAR);'. Więc teoretycznie możesz rzucić tę linię –

+0

@Mindinda Green, jak mogę zmienić kolor farby na płótnie przy każdym kliknięciu przycisku w mojej aktywności, aby mógł nadać różne kolory tła – Erum

+0

@Erum Hannan Po prostu zapisz kolor w metodzie onClick przycisku ten kolor jako tło z canvas.drawColor z tym w onDraw. –