目标只是绘制一个位图,并在其顶部绘制可以删除位图底层区域的形状。
我创建了简单的概念证明代码,试图理解我应该如何解决这个问题。在这里的各个主题中,我发现了许多关于使用的提示:
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]);
}
}
}
}
}
这是测试的结果:
CLEAR模式位于左上角,显示为黑色。
在我试图使用它的另一个例子中,我有一个DialogFragment,其中CLEAR模式擦除整个DialogFragment,以便可以看到下面的活动。因此我在这次测试中使用了许多不同的背景颜色。
这可能是清除整个活动的像素,就像其他例子让我相信的那样吗?我原以为只有与视图相关的画布像素才能被删除,但在我的另一个例子中,自定义视图,底层图像视图和DialogFragment背景的像素都被清除了。
有人可以帮助我了解到底发生了什么,以及为什么我会如此严重错误?
感谢。
修改 我复制了一个证实我怀疑的例子。添加此精确自定义视图时,但在DialogFragment中,基础活动将变为可见。
对我来说,这似乎是一个非常明确的指标,Mode.CLEAR
也在某种程度上抹去了下方视图的画布?我的猜测是第一个例子中的黑色是顶级视图的黑色?
我在想我在某处做错了什么:S
答案 0 :(得分:36)
问题是硬件加速。对于使用CLEAR绘制的特定视图,将其关闭。如果您正在使用自定义视图,请在构造函数中执行此操作:
if (android.os.Build.VERSION.SDK_INT >= 11)
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
您还可以在视图引用上调用setLayerType。
答案 1 :(得分:14)
我没有看到任何意外。在Mode.CLEAR
的特定情况下,目标的颜色和alpha都会被清除,这样就可以显示黑色背景。这个utility允许我们尝试各种模式,颜色和alpha值,而源可以提供一些见解。在下面的(有点过时)图像中,CLEAR
区域显示平台的PanelUI
代表提供的微弱细条纹灰色。
答案 2 :(得分:0)
正如Romain Guy在这里指出的那样:google stuff你需要在Bitmap上写字,而不是你想要清除的圆圈的画布,然后将它设置为你视图中的主Canvas。所以,做一些像:
// 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(....);
希望这有帮助。