【问题标题】:Android: Shader behave different in 'onDraw(canvas)' and 'new Canvas(bitmap)'Android:着色器在“onDraw(canvas)”和“new Canvas(bitmap)”中的行为不同
【发布时间】:2011-03-08 10:32:48
【问题描述】:

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

请在我的自定义视图中找到以下代码:

@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) 获得)和 canvas2(使用 new Canvas(bitmap) 创建)中做同样的事情

但是,两者绘制不同的着色器效果如下:

为什么着色器效果不同?

【问题讨论】:

    标签: android


    【解决方案1】:

    考虑第二列的黑色矩形:

    PorterDuff.MODE.DST_IN 定义为 [Sa*Da, Sa*Dc]。由于目标像素是恒定的不透明灰色 (Da=1),因此结果的 Alpha 通道将设置为线性渐变中的 Alpha 通道,范围从 0.5 到 1。

    您的问题就在那里...在第二列中,您将窗口画布的像素设置为部分透明。从下面透出什么?窗口背景,仍然是默认的黑色。

    在第 3 列中,您首先绘制到离屏位图,然后将部分透明的离屏位图绘制到窗口画布。这是因为传入的像素(来自屏幕外位图)并没有完全替换已经存在的像素,而是与目标缓冲区混合(在 PorterDuff 术语中,我认为它相当于 SRC_ATOP)。

    【讨论】:

    • 感谢您的解释。但是我仍然不清楚源和目标,目标不是 drawRect() 调用之前画布的状态(我的意思是,在其上绘制图像的画布)。而是创建时的状态。我将第 3 列源代码更改为 //3rd Column Bitmap bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight()*2, Config.RGB_565); bitmap.eraseColor(Color.GRAY);然后与第二列相同。看起来我们无法将画布从 onDraw(canvas) 更改为屏幕外的位图画布?
    • 如果您使用 Config.RGB_565,您将丢弃离屏位图的 Alpha 通道,因此在绘制到窗口画布时无法混合。它只会替换目标像素。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-07
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    相关资源
    最近更新 更多