2012-08-07 144 views
15

我想要在Canvas上繪製圖形,使顏色具有可加性。例如,我想產生這樣的:
Proper additive colors如何用alpha繪製?

但是,相反,我得到這個:
My results

注意,半白,一半黑的背景是故意的,只是爲了看看阿爾法如何與這兩個交互背景。我很樂意在任何背景下進行這項工作。這裏是我的代碼:

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

有人可以幫助我瞭解如何在Android圖形中添加顏色塗料?

回答

26

你在正確的軌道上。有在你的代碼3個主要問題:

  • 您需要設置XFER模式ISO彩色濾光片
  • 使用臨時位圖繪製圖像
  • 阿爾法應爲0xFF,以獲得您正在尋找的結果

這是我用xfer模式得到的結果。我在做什麼 - 將所有內容都繪製到臨時位圖中,然後將整個位圖渲染到主畫布上。

xfer mode rules

你問爲什麼你需要臨時的位圖?好問題!如果您在主畫布上繪製所有內容,則您的顏色將與主畫布背景顏色混合,因此所有顏色都會混亂。透明的臨時位圖有助於保持您的顏色不會丟失其他部分的UI

請確保您沒有在onDraw()中分配任何東西 - 您將很快以這種方式耗盡內存..還要確保您已經回收了您的臨時位圖當你不再需要它。

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

非常感謝Pavel;太快了! – 2012-08-07 02:59:27

+3

順便說一下,你會知道與SDK版本8兼容的PorterDuff.Mode.ADD的替代方案嗎?該文檔說ADD是在第8版中添加的,但它在於。它真的在版本11中引入,並在一些舊的設備上崩潰,而這些設備應該不允許安裝我的小部件。 – 2012-12-15 05:18:10

+1

這太棒了!你可以將這種技術應用於彼此重疊的位圖嗎? – 2013-05-15 20:46:27

2

再次感謝帕維爾。如果我自己想出來,那將是非常困難的。我正在回答自己的問題,以便更好地深入細節,但我已經接受你的答案。

你說得對,我寧願不必創建和管理離屏位圖(和畫布)。這就是爲什麼我提到黑色或白色背景可以很好地完成這項工作。

在我看到有用的東西之前,我從不擔心表現,但在此之後我會分享您的警惕。編輯你的版本來解決這個問題,並刪除這些成員,下面給出了實現。

這是否健壯?請注意對Canvas.drawColor()的兩次調用,我懷疑它們也可以合併爲一個。

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

此解決方案也是正確的。我建議使用單獨的位圖,因爲通常你只想混合你想要的顏色,而不會弄亂UI的其餘部分。對你的代碼唯一的一條評論是'canvas.drawColor(Color.BLACK);'調用是無用的,因爲你通過調用'canvas.drawColor(Color.TRANSPARENT,Mode.CLEAR);'來清除整個區域。所以理論上你可以放棄這一行 – 2012-08-07 06:50:54

+0

@Melinda Green如何在每次點擊活動時改變畫布的顏色,以便它可以給出不同的背景顏色 – Erum 2014-11-10 11:49:03

+0

@Erum Hannan只需在按鈕的onClick方法中存儲顏色並設置該顏色作爲背景與canvas.drawColor與它在onDraw。 – 2014-11-10 23:43:43