使用alpha渐变将位图绘制到画布上

8
我想在画布Canvas上绘制一个Bitmap,并应用(线性)alpha渐变。重要的是,我不想在图像上叠加任何其他颜色; 背景(来自我将此Canvas绘制到其后面的View)只需“透过”即可。 为了说明,我的目标是这样的(棋盘格图案表示View后面的内容):

linear alpha gradient

人们可能会认为我可以像这样做:
Bitmap bitmap = ...;
Paint paint = new Paint();
paint.setShader(new LinearGradient(0, 0, 100, 0, FROM, TO, Shader.TileMode.CLAMP));
canvas.drawBitmap(bitmap, 0, 0, paint);

但是在这里,LinearGradientFROMTO参数需要是颜色,而不是透明度值;因此,我没有看到任何指定例如FROM完全透明和TO完全不透明(无需应用任何颜色叠加)的方法。


检查这个库 https://github.com/chiuki/android-graphics-demo - PN10
@Cactus 我看到 LinearGradient 需要 color0(起始颜色)和 color1(结束颜色)是整数。它是否允许使用 rbga 值的小数表示,还是只允许 rgb,或者它期望完全不同的内容?文档对这个整数值的解释相当不清楚。https://developer.android.com/reference/android/graphics/LinearGradient.html - d.j.brown
@d.j.brown:这是一个32位的ARGB值。 - Cactus
2个回答

12

使用ComposeShader,像这样:

class V extends View {
    Bitmap bitmap;
    Paint paint = new Paint();

    public V(Context context) {
        super(context);
        bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.chrome);
        Shader shaderA = new LinearGradient(0, 0, bitmap.getWidth(), 0, 0xffffffff, 0x00ffffff, Shader.TileMode.CLAMP);
        Shader shaderB = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        paint.setShader(new ComposeShader(shaderA, shaderB, PorterDuff.Mode.SRC_IN));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), paint);
    }
}

当然,您需要更改“LinearGradient”构造函数参数以获得所需的渐变。 - pskink
我原则上更喜欢这个,比我能想出来的那个更好。但是不需要创建一个离屏的“Canvas”是否也有性能优势? - Cactus
1
我认为这不仅与 CPU 时钟有关,还与创建离屏 Bitmap 相关的内存消耗有关。顺便说一句,你可以像使用 Canvas#saveLayer 一样做(无需额外创建 Bitmap),但我仍然认为 ComposeShader 更接近底层 GPU 操作。 - pskink
这段代码能否与Picasse / Glide结合使用?你能举个例子吗?:-) - KayD

6

根据这个与掩码有关的回答,我可以使用第二个屏幕外画布来实现这一点:

Bitmap backing = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
{
    Canvas offscreen = new Canvas(backing);
    offscreen.drawBitmap(bitmap, 0, 0, null);
    Paint paint = new Paint();
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    paint.setShader(new LinearGradient(0, 0, 100, 0, 0x00000000, 0xFF000000, Shader.TileMode.CLAMP));
    offscreen.drawRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), paint);
}
canvas.drawBitmap(backing, 0, 0, null);

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