2010-04-12 109 views
17

我目前正在寻找一种方法来使用黑白位图来屏蔽Android上另一个位图或Drawable的Alpha通道。我很好奇最好的方式是做什么。对于如何做到这一点,我当然有一些想法,但它们并不是最优的。屏蔽Android上的Drawable/Bitmap

我需要能够每隔一段时间对图像应用一个新的遮罩(黑白位图每隔几秒就会改变一次)。

任何有关如何实现这一目标的反馈将不胜感激。

+0

我试图使用掩码位图的黑色部分来设置其他位图上的相应像素的Alpha通道/ Drawable为0. – 2010-04-12 19:52:21

回答

3

我得到它的工作,所以它是这样的

// we first same the layer, rectF is the area of interest we plan on drawing 
    // this will create an offscreen bitmap 
    canvas.saveLayer(rectF, null, Canvas.MATRIX_SAVE_FLAG 
      | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG 
      | Canvas.FULL_COLOR_LAYER_SAVE_FLAG 
      | Canvas.CLIP_TO_LAYER_SAVE_FLAG); 

    // draw our unmasked stuff 
    super.draw(canvas); 
    // We same a layer again but this time we pass a paint object to mask 
    // the above layer 
    maskPaint = new Paint() 
    maskPaint.setColor(0xFFFFFFFF); 
    maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); 

    canvas.saveLayer(rectF, maskPaint, 
      Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG 
        | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG 
        | Canvas.FULL_COLOR_LAYER_SAVE_FLAG 
        | Canvas.CLIP_TO_LAYER_SAVE_FLAG); 
    // we draw the mask which is black and white. In my case 
    // I have a path, and I use a blurPaint which blurs the mask slightly 
    // You can do anti aliasing or whatever you which. Just black & white 
    canvas.drawPath(path, blurPaint); 
    // We restore twice, this merges the results upward 
    // as each saveLayer() allocates a new drawing bitmap 
    canvas.restore(); 
    canvas.restore(); 
+0

如果重写onDraw方法,而不是'super.draw(canvas)'应该有'super.onDraw(canvas)'。否则,最终会出现StackOverflow错误的无限循环。 – Speedy 2013-04-05 08:21:42

+0

我在自定义视图的'onDraw'中做了与上面相同的事情,但是看起来'saveLayer'很昂贵,所以我没有为我的视图设置一个硬件层('View.setLayerType(LAYER_TYPE_HARDWARE,paint) ')。更多信息:http://stackoverflow.com/a/33483016/4747587 – Henry 2015-11-02 17:12:25

2

我并不完全清楚你要做什么,但我相信BitmapDrawableLayerDrawable的组合可能会起作用。 BitmapDrawable将允许您使用您的位图作为Drawables,然后您可以使用LayerDrawable将遮罩层叠到另一个Drawable上。

+0

我会检查出来,谢谢。 – 2010-04-12 19:49:52

1

在API Demo中使用Xfermodes示例我能够使用应用于Paint对象的PorterDuffXfermode在画布上混合两个位图。这工作正是我需要它。

+12

你可以添加更多的细节? – Casebash 2010-04-29 02:25:30

5

我的解决方案接近@ over_optimistic的解决方案,少一个saveLayer()调用。我使用Drawable mask而不是路径,在我的情况下它是一张光盘。

我宣布这些变量作为字段(这是很好的做法的onDraw方法之外分配内存):

private Paint maskingPaint = new Paint(); 
private Drawable mask = <insert your drawable here> 

然后,外面的onDraw(),设置对象的地方:

// Xfermode won't work if hardware accelerated 
setLayerType(View.LAYER_TYPE_SOFTWARE, null); 

// Using destination shape as a mask 
// For a good explanation of PorterDuff transfer modes : http://ssp.impulsetrain.com/porterduff.html 
maskingPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 
maskingPaint.setAntiAlias(true); 

// Position the mask 
mask.setBounds(<insert your mask bounds here>); 

最后,onDraw()方法应用蒙版:

@Override 
protected synchronized void onDraw(Canvas canvas) 
{ 
    // Draw the mask first, making it the PorterDuff destination 
    mask.draw(canvas); 

    // Save the layer with the masking paint, that will be applied on restore() 
    // Using CLIP_TO_LAYER_SAVE_FLAG to avoid any overflow of the masked image outside the mask bounds. 
    Rect bounds = mask.getBounds(); 
    canvas.saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, maskingPaint, 
      Canvas.CLIP_TO_LAYER_SAVE_FLAG); 

    // Draw the shape offscreen, making it the PorterDuff source 
    super.onDraw(canvas); 

    // Apply the source to the destination, using SRC_IN transfer mode 
    canvas.restore(); 
} 

为了更好地理解o f传输模式,我提到http://ssp.impulsetrain.com/porterduff.html。 该页面非常有趣。之后,使用相同类型的代码,您可以获得比单纯的面具更多的功能!

+0

完美的解决方案。其他人有点太长了。 – Jona 2015-02-17 00:46:42

+0

国际海事组织比接受的答案更好,我更喜欢在路径上绘制 – 2017-03-03 08:36:44