2012-07-05 96 views
27

目標僅僅是繪製位圖並在其上方繪製刪除位圖底層區域的形狀。PorterduffXfermode:清除位圖的一部分

我已經創建了概念代碼的簡單證明,試圖理解我應該如何去做這件事。在這裏的各個線程我發現無數的提示如何使用:

android.graphics.PorterDuff.Mode.CLEAR 

下面的代碼只是創建一個具有藍色背景的屏幕並添加了一個自定義視圖。該視圖在其畫布上繪製了一個粉紅色背景,位圖圖像(帶有輕微邊框以顯示粉紅色背景),以及黃色覆蓋圓圈表示每個PorterDuffXfermode。

import android.app.Activity; 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.PorterDuffXfermode; 
import android.graphics.Paint.Style; 
import android.graphics.PorterDuff.Mode; 
import android.graphics.RectF; 
import android.os.Bundle; 
import android.view.View; 
import android.view.Window; 
import android.widget.RelativeLayout; 

public class Test extends Activity { 
    Drawing d = null; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     requestWindowFeature(Window.FEATURE_NO_TITLE); 

     RelativeLayout.LayoutParams rlp = null; 

     // Create the view for the xfermode test 
     d = new Drawing(this); 
     rlp = new RelativeLayout.LayoutParams(600, 900); 
     rlp.addRule(RelativeLayout.CENTER_IN_PARENT); 
     d.setLayoutParams(rlp); 

     RelativeLayout rl = new RelativeLayout(this); 
     rl.setBackgroundColor(Color.rgb(0, 0, 255)); 
     rl.addView(d); 

     // Show the layout with the test view 
     setContentView(rl); 
    } 

    public class Drawing extends View { 
     Paint[] pDraw = null; 
     Bitmap bm = null; 

     public Drawing(Context ct) { 
      super(ct); 

      // Generate bitmap used for background 
      bm = BitmapFactory.decodeFile("mnt/sdcard/Pictures/test.jpg"); 

      // Generate array of paints 
      pDraw = new Paint[16]; 

      for (int i = 0; i<pDraw.length; i++) { 
       pDraw[i] = new Paint(); 
       pDraw[i].setARGB(255, 255, 255, 0); 
       pDraw[i].setStrokeWidth(20); 
       pDraw[i].setStyle(Style.FILL); 
      } 

      // Set all transfer modes 
      pDraw[0].setXfermode(new PorterDuffXfermode(Mode.CLEAR)); 
      pDraw[1].setXfermode(new PorterDuffXfermode(Mode.DARKEN)); 
      pDraw[2].setXfermode(new PorterDuffXfermode(Mode.DST)); 
      pDraw[3].setXfermode(new PorterDuffXfermode(Mode.DST_ATOP)); 
      pDraw[4].setXfermode(new PorterDuffXfermode(Mode.DST_IN)); 
      pDraw[5].setXfermode(new PorterDuffXfermode(Mode.DST_OUT)); 
      pDraw[6].setXfermode(new PorterDuffXfermode(Mode.DST_OVER)); 
      pDraw[7].setXfermode(new PorterDuffXfermode(Mode.LIGHTEN)); 
      pDraw[8].setXfermode(new PorterDuffXfermode(Mode.MULTIPLY)); 
      pDraw[9].setXfermode(new PorterDuffXfermode(Mode.SCREEN)); 
      pDraw[10].setXfermode(new PorterDuffXfermode(Mode.SRC)); 
      pDraw[11].setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP)); 
      pDraw[12].setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 
      pDraw[13].setXfermode(new PorterDuffXfermode(Mode.SRC_OUT)); 
      pDraw[14].setXfermode(new PorterDuffXfermode(Mode.SRC_OVER)); 
      pDraw[15].setXfermode(new PorterDuffXfermode(Mode.XOR)); 
     } 

     @Override 
     public void onDraw(Canvas canv) { 
      // Background colour for canvas 
      canv.drawColor(Color.argb(255, 255, 0, 255)); 

      // Draw the bitmap leaving small outside border to see background 
      canv.drawBitmap(bm, null, new RectF(15, 15, getMeasuredWidth() - 15, getMeasuredHeight() - 15), null); 

      float w, h; 
      w = getMeasuredWidth(); 
      h = getMeasuredHeight(); 

      // Loop, draws 4 circles per row, in 4 rows on top of bitmap 
      // Drawn in the order of pDraw (alphabetical) 
      for(int i = 0; i<4; i++) { 
       for(int ii = 0; ii<4; ii++) { 
        canv.drawCircle((w/8) * (ii * 2 + 1), (h/8) * (i * 2 + 1), w/8 * 0.8f, pDraw[i*4 + ii]); 
       } 
      } 
     } 
    } 

} 

這是試驗的結果:

enter image description here

清澈模式是左上角,其示出爲黑色。

在另一個我試圖使用它的例子中,我有一個DialogFragment,其中CLEAR模式擦除了整個DialogFragment,這樣可以看到下面的活動。因此,我在這個測試中使用了許多不同背景顏色的原因。

難道這可能是清除整個活動像素像其他例子讓我相信嗎?我會認爲只有與視圖相關的畫布像素可以被擦除,但在另一個例子中,自定義視圖,底層圖像視圖和DialogFragment背景的像素全部被清除。

有人能幫我理解究竟發生了什麼,爲什麼我會這麼糟糕嗎?

謝謝。

編輯: 我紛紛轉載,確認了我的懷疑的例子。添加此確切的自定義視圖時,但在DialogFragment中,基礎活動變爲可見。

enter image description here

這似乎是一個非常明確的指標,對我來說,Mode.CLEAR以某種方式擦除的下方還有意見畫布?我的猜測是第一個例子中的黑色是頂級視圖中的黑色?

我想我做的事情很不對勁的地方:S

回答

34

的問題是硬件加速。使用CLEAR將特定的View視圖關閉。如果您使用的是自定義視圖,在構造函數做到這一點:

if (android.os.Build.VERSION.SDK_INT >= 11) 
{ 
    setLayerType(View.LAYER_TYPE_SOFTWARE, null); 
} 

您也可以撥打setLayerType在視圖上的參考。

+2

謝謝...讓我的一天! –

+1

它會減慢繪畫,不是嗎? – sandrstar

+0

這應該是被接受的答案。超級有用。謝謝! –

14

我看不出有什麼意外。在Mode.CLEAR的特定情況下,清除目的地的顏色和alpha,這允許顯示黑色背景。這utility允許人們嘗試各種模式,顏色和alpha值,並可以提供一些見解。在下面的(有些過時的)圖片中,CLEAR區域顯示平臺的PanelUI代表提供的微弱細條紋灰色。

image

+0

謝謝,這很有道理。把我的問題應用於此。正如你所說,你正確地看到了清晰區域的底層背景。爲什麼我看不到藍色(我可以理解爲什麼不是粉色)背景?藍色是不同的視圖,爲什麼像素在自定義視圖畫布中不透明? (如上圖)。如果我將ImageView放在它後面或其他任何地方,我仍然看不到它,只有黑色。 當在DialogFragment中做同樣的事情時,這個方法在我的整個Dialog(以及視圖)中逐字地繪製了一個洞。那麼是否由於某種原因清除了所有圖層? –

+0

也就是說,我怎樣才能完全像你的圖像那樣做(通過清除圖形區域來顯示背景? –

+1

嘗試在'SrcOver'模式下調整'Src'顏色的alpha以查看效果。[源代碼](https://sites.google.com/site/drjohnbmatthews/composite/source-code)也可能提供一些見解,並且有一個相關示例[此處](http://stackoverflow.com/a/7824225/230513 ) – trashgod

0

正如Romain Guy在這裏指出的那樣:google stuff您需要在位圖上書寫,而不是帶有要清除圓圈的畫布,然後將其設置爲視圖中的主畫布。所以,做類似的事情:

// Generate bitmap used for background 
      bm = BitmapFactory.decodeFile("mnt/sdcard/Pictures/test.jpg"); 

// Create the paint and set the bitmap 
Canvas temp = new Canvas(bm.getHeight(), bm.getWidth, Config.ARGB_8888); 

// in onDraw() 
temp.drawCircle((w/8) * (ii * 2 + 1), (h/8) * (i * 2 + 1), w/8 * 0.8f, pDraw[i*4 + ii]); 

// After loop 
canvas.drawBitmap(....); 

希望這會有所幫助。