PorterDuffXfermode DST_IN未按预期工作

7
我正在尝试加速我们正在进行的绘图过程(使用 alpha 透明度绘制弧线的一部分),并尝试将整个弧线缓存到一个单独的位图中,并使用 alpha 蒙版进行选择性显示。根据我所做的研究(Android 的 Xfermodes API 演示、this examplethis tool),如果我有以下两个图形:

enter image description here

enter image description here

并使用以下内容进行绘制:

Xfermode DST_IN = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

canvas.drawBitmap(circle, 0, 0, paint);
paint.setXfermode(DST_IN);
canvas.drawBitmap(arc, 0, 0, paint);
paint.setXfermode(null);

我应该得到这个结果:

enter image description here

目标图像(圆)被裁剪到绘制源图像(弧)的区域。然而,我得到了完整的圆形。如果只绘制弧,它会出现在正确的位置,如果使用DST_OUT,则得到预期结果的反向结果(圆的另外三个象限)。

我还确保为此视图禁用了硬件渲染,以防Xfermode存在问题,但没有任何区别。

我将其拆分为一个单独的项目,尝试用最简单的方法使其正常工作,并且使用以下代码,仍然存在相同的问题:

public class ClippedView extends View {
    private Xfermode DST_IN, DST_OUT;
    private Paint paint;

    public ClippedView(Context context) {
        super(context);
        init();
    }

    private void init() {
        setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        DST_IN = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
        DST_OUT = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(Color.GREEN);
        canvas.drawRect(0, 0, getWidth() / 2, getHeight() / 2, paint);
        paint.setColor(Color.BLACK);
        paint.setXfermode(DST_IN);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, paint);
        paint.setXfermode(null);
    }
}

我使用方法不正确吗?是我遗漏了什么吗?还是我发现了一个bug?:)


我曾经面临和您相同的问题:我试图将画布裁剪成圆角矩形,但DST_IN无法正常工作。经过长时间的研究,我发现只有在调用canvas.drawBitmap()时PorterDuff.DST_IN才能起作用。因此,canvas.drawCircle()、canvas.drawRoundedRect()等是不起作用的。您可以先将您的圆形绘制到位图中,然后再绘制位图。 - vadiole
1个回答

9

有一个更便宜和更简单的方法来实现这个目标:使用裁剪。Canvas.clipRect()就足够了。你的解决方案会消耗很多填充率。你可以使用SRC_IN而不是DST_IN来获得你想要的效果。但要小心:它只能在透明Bitmap或层中工作。当你直接在屏幕上绘制时,目标已经被窗口背景填充。


谢谢!我没有意识到onDraw画布包括窗口背景——这让发生的事情更有意义了。我选择了位图路线,因为没有简单的方法来绘制一个封闭的弧形路径,然后在clipPath()中使用它。除非你有其他建议,否则我会找到一条绘制该路径的路线。 - Kevin Coppock
我有一个视图需要每1/25秒刷新一次。每次创建一个新的透明Bitmap,然后使用PotterDuff.Mode会消耗很多FPS和内存,所以这种方法失败了。我尝试在屏幕上绘制(在onDraw()提供的Canvas上),但问题是每个PotterDuff.Mode.CLEAR都会使我的Canvas变黑而不是透明(没有将Bitmap绑定到Canvas)。所以我理解的问题是“目标已经被窗口背景填充”?那么如何创建一个具有透明背景和PotterDuff.Mode.SRC_IN的快速刷新视图呢?什么意思是“它将在图层中工作”? - cadavre
不要每次都创建新的位图,重复使用它。 - Romain Guy
@RomainGuy 有没有教程或资源可以学习关于填充率和其他属性的知识? - Thracian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接