Android:在' onDraw(canvas)'和' new Canvas(bitmap)'中,着色器的行为不同

3

我正在尝试创建反射阴影并遇到了一个问题。

请查看我的自定义视图中的以下代码:

@Override
protected void onDraw(Canvas canvas) {
    //prepare
    canvas.drawColor(Color.GRAY);
    Bitmap source = BitmapFactory.decodeResource(getResources(), R.drawable.icon);

    //First Column
    canvas.drawBitmap(source, 0, 0, new Paint());

    //2nd Column
    canvas.drawBitmap(source, source.getWidth(), 0, new Paint());

    //Reflection
    Matrix matrix = new Matrix();
    matrix.preScale(1.0f, -1.0f);
    matrix.postTranslate(source.getWidth(), source.getHeight()*2);
    canvas.drawBitmap(source, matrix, new Paint());

    Paint paint2 = new Paint();
    LinearGradient shader = new LinearGradient(
            source.getWidth()*3/2, 
            source.getHeight(),
            source.getWidth()*3/2,
            source.getHeight()*2,
            0x7FFFFFFF, 0x00FFFFFF, TileMode.CLAMP);
    paint2.setShader(shader);
    paint2.setXfermode(new PorterDuffXfermode(
            android.graphics.PorterDuff.Mode.DST_IN));
    canvas.drawRect(
            source.getWidth(), 
            source.getHeight(),
            source.getWidth()*2,
            source.getHeight()*2,
            paint2);

    //3rd Column
    Bitmap bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight()*2, Config.ARGB_8888);
    Canvas canvas2 = new Canvas(bitmap);
    canvas2.drawBitmap(source, 0, 0,  new Paint());
    matrix = new Matrix();
    matrix.preScale(1.0f, -1.0f);
    matrix.postTranslate(0, source.getHeight()*2);
    canvas2.drawBitmap(source, matrix, new Paint());


    paint2 = new Paint();
    shader = new LinearGradient(
            source.getWidth()*1/2, 
            source.getHeight(),
            source.getWidth()*1/2,
            source.getHeight()*2,
            0x7FFFFFFF, 0x00FFFFFF, TileMode.CLAMP);
    paint2.setShader(shader);
    paint2.setXfermode(new PorterDuffXfermode(
            android.graphics.PorterDuff.Mode.DST_IN));
    canvas2.drawRect(
            0, 
            source.getHeight(),
            source.getWidth(),
            source.getHeight()*2,
            paint2);

    canvas.drawBitmap(bitmap, source.getWidth()*2,0, new Paint());
}

我正在canvas中进行同样的操作(从onDraw(canvas)获取),并且在使用new Canvas(bitmap)创建的canvas2中进行操作。

但是,两者绘制的着色器效果不同,如下所示: different shader effect

为什么着色器效果会不同呢?

1个回答

3
考虑第二列中的黑色矩形:
PorterDuff.MODE.DST_IN被定义为[Sa * Da,Sa * Dc]。由于目标像素是一个不透明的灰色常量(Da = 1),结果的alpha通道将设置为线性渐变的alpha通道,该通道从0.5到1不等。
问题就在这里...在第二列中,您正在将窗口画布的像素部分透明。从下面透过来的是什么?窗口背景仍然是默认的黑色。
在第三列中,您首先绘制到一个离屏位图,然后在之后将部分透明度的离屏位图绘制到窗口画布上。这有效是因为传入的像素(来自离屏位图)并不完全替换已经存在的像素,而是与目标缓冲区混合(在PorterDuff术语中,我认为它相当于SRC_ATOP)。

谢谢你的解释。但是我仍然不清楚源和目标是什么,目标不是在drawRect()调用之前画布的状态(我的意思是,在其上绘制了图像的画布),而是创建时的状态。我将第三列源代码更改为 //第三列 Bitmap bitmap = Bitmap.createBitmap(source.getWidth(),source.getHeight()* 2,Config.RGB_565); bitmap.eraseColor(Color.GRAY); 然后得到与第二列相同的结果。看来我们不能从onDraw(canvas)中更改画布以使其表现为屏幕外位图画布? - Sudar Nimalan
如果您使用Config.RGB_565,则会丢弃离屏位图的Alpha通道,因此在绘制到窗口画布时无法进行混合。它将仅替换目标像素。 - Reuben Scratton

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