【问题标题】:How to paint with alpha?如何用阿尔法绘画?
【发布时间】:2012-08-07 01:09:31
【问题描述】:

我想在 Canvas 上绘制图形,这样颜色是相加的。例如,我想生成这个:

但相反,我得到了这个:

请注意,半白半黑的背景是有意的,只是为了看看 alpha 如何与两种背景相互作用。我很乐意在这两种背景下完成这项工作。这是我的代码:

public class VennColorsActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        class VennView extends View {
            public VennView(Context context) {
                super(context);
            }

            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
                int alpha = 60, val = 255;
                int ar = Color.argb(alpha, val, 0, 0);
                int ag = Color.argb(alpha, 0, val, 0);
                int ab = Color.argb(alpha, 0, 0, val);
                float w = canvas.getWidth();
                float h = canvas.getHeight();
                float cx = w / 2f;
                float cy = h / 2;
                float r = w / 5;
                float tx = (float) (r * Math.cos(30 * Math.PI / 180));
                float ty = (float) (r * Math.sin(30 * Math.PI / 180));
                float expand = 1.5f;
                Paint paint = new Paint();
                paint.setColor(Color.WHITE);
                canvas.drawRect(new Rect(0, 0, (int) w, (int) (h / 2)), paint);
                PorterDuff.Mode mode = android.graphics.PorterDuff.Mode.ADD;
                paint = new Paint(Paint.ANTI_ALIAS_FLAG);
                paint.setColorFilter(new PorterDuffColorFilter(ar, mode));
                paint.setColor(ar);
                canvas.drawCircle(cx, cy - r, expand * r, paint);
                paint.setColorFilter(new PorterDuffColorFilter(ag, mode));
                paint.setColor(ag);
                canvas.drawCircle(cx - tx, cy + ty, expand * r, paint);
                paint.setColorFilter(new PorterDuffColorFilter(ab, mode));
                paint.setColor(ab);
                canvas.drawCircle(cx + tx, cy + ty, expand * r, paint);
            }
        }
        this.setContentView(new VennView(this));
    }
}

有人可以帮我了解如何在 Android 图形中使用加色进行绘画吗?

【问题讨论】:

    标签: android


    【解决方案1】:

    你在正确的轨道上。您的代码中有 3 个主要问题:

    • 您需要设置 xfer 模式 iso 滤色器
    • 使用临时位图渲染图像
    • Alpha 应为 0xFF 以获得您正在寻找的结果

    这是我通过使用 xfer 模式得到的结果。我在做什么 - 将所有内容绘制到临时位图中,然后将整个位图渲染到主画布。

    你问为什么需要临时位图?好问题!如果您在主画布上绘制所有内容,您的颜色将与主画布背景颜色混合,因此所有颜色都会混乱。透明的临时位图有助于让您的颜色远离 UI 的其他部分

    请确保您没有在 onDraw() 中分配任何内容 - 这样您很快就会耗尽内存。同时确保您在不再需要临时位图时回收了它。

    package com.example.stack2;
    
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Bitmap.Config;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PorterDuff.Mode;
    import android.graphics.PorterDuffXfermode;
    import android.os.Bundle;
    import android.view.View;
    
    public class YouAreWelcome extends Activity {
    
        Bitmap tempBmp = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
        Canvas c = new Canvas();
        Paint paint = new Paint();
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            class VennView extends View {
                public VennView(Context context) {
                    super(context);
    
                }
    
                protected void onDraw(Canvas canvas) {
                    super.onDraw(canvas);
                    if(tempBmp.isRecycled() || tempBmp.getWidth()!=canvas.getWidth() || tempBmp.getHeight()!=canvas.getHeight())
                    {
                        tempBmp.recycle();
                        tempBmp = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888);
                        c.setBitmap(tempBmp);
                    }
    
                        //clear previous drawings
                    c.drawColor(Color.TRANSPARENT, Mode.CLEAR);
    
                    int alpha = 255, val = 255;
                    int ar = Color.argb(alpha, val, 0, 0);
                    int ag = Color.argb(alpha, 0, val, 0);
                    int ab = Color.argb(alpha, 0, 0, val);
                    float w = canvas.getWidth();
                    float h = canvas.getHeight();
                    float cx = w / 2f;
                    float cy = h / 2;
                    float r = w / 5;
                    float tx = (float) (r * Math.cos(30 * Math.PI / 180));
                    float ty = (float) (r * Math.sin(30 * Math.PI / 180));
                    float expand = 1.5f;
                    paint.setAntiAlias(true);
                    paint.setXfermode(new PorterDuffXfermode(Mode.ADD));
                    paint.setColor(ar);
                    c.drawCircle(cx, cy - r, expand * r, paint);
                    paint.setColor(ag);
                    c.drawCircle(cx - tx, cy + ty, expand * r, paint);
                    paint.setColor(ab);
                    c.drawCircle(cx + tx, cy + ty, expand * r, paint);
                    canvas.drawBitmap(tempBmp, 0, 0, null);
                }
            }
            this.setContentView(new VennView(this));
        }
    }
    

    【讨论】:

    • 非常感谢,帕维尔;也很快!
    • 顺便说一句,您知道与 SDK 版本 8 兼容的 PorterDuff.Mode.ADD 替代方案吗?文档说 ADD 是在版本 8 中添加的,但它是在说谎。它确实是在版本 11 中引入的,并且在一些不应该被允许安装我的小部件的旧设备上崩溃。
    • 这太棒了!你能把这种技术应用到相互重叠的位图上吗?
    • @bot_bot 我希望如此,因为我可能会以这种方式重新实现我的应用程序。
    【解决方案2】:

    再次感谢帕维尔。这对我来说很难自己弄清楚。我正在回答我自己的问题以更好地深入了解细节,但我已接受您的问题作为最佳答案。

    您说得对,我不想创建和管理屏幕外位图(和画布)。这就是为什么我提到黑色或白色背景可以很好地完成这项工作的原因。

    在我看到某些东西有效之前,我从不关心性能,但在那之后我和你一样谨慎。编辑您的版本以解决该问题并删除这些成员会提供以下实现。

    这很健壮吗?请注意对 Canvas.drawColor() 的两个调用,我怀疑它们也可以合并为一个。

    package com.superliminal.android.test.venn;
    
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PorterDuff.Mode;
    import android.graphics.PorterDuffXfermode;
    import android.os.Bundle;
    import android.view.View;
    
    public class VennColorsActivity extends Activity {
        private Paint paint = new Paint();
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            class VennView extends View {
                public VennView(Context context) {
                    super(context);
                }
    
                @Override
                protected void onDraw(Canvas canvas) {
                    super.onDraw(canvas);
                    canvas.drawColor(Color.BLACK);
                    canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
                    int alpha = 255, val = 255;
                    int ar = Color.argb(alpha, val, 0, 0);
                    int ag = Color.argb(alpha, 0, val, 0);
                    int ab = Color.argb(alpha, 0, 0, val);
                    float w = canvas.getWidth();
                    float h = canvas.getHeight();
                    float cx = w / 2f;
                    float cy = h / 2;
                    float r = w / 5;
                    float tx = (float) (r * Math.cos(30 * Math.PI / 180));
                    float ty = (float) (r * Math.sin(30 * Math.PI / 180));
                    float expand = 1.5f;
                    paint.setAntiAlias(true);
                    paint.setXfermode(new PorterDuffXfermode(Mode.ADD));
                    paint.setColor(ar);
                    canvas.drawCircle(cx, cy - r, expand * r, paint);
                    paint.setColor(ag);
                    canvas.drawCircle(cx - tx, cy + ty, expand * r, paint);
                    paint.setColor(ab);
                    canvas.drawCircle(cx + tx, cy + ty, expand * r, paint);
                }
            }
            setContentView(new VennView(this));
        }
    }
    

    【讨论】:

    • 这个解决方案也是正确的。我建议使用单独的位图,因为通常你只想混合你想要的颜色,而不是弄乱 UI 的其余部分。对您的代码的唯一一条注释是 canvas.drawColor(Color.BLACK); 调用是无用的,因为您通过调用 canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR); 清除了整个区域。所以理论上你可以放弃这条线
    • @Melinda Green 如何在我的活动中单击每个按钮时更改画布的油漆颜色,以便它可以提供不同的背景颜色
    • @Erum Hannan 只需在按钮的 onClick 方法中存储一种颜色,然后使用 canvas.drawColor 将该颜色设置为背景,并在 onDraw 中使用它。
    • @MelindaGreen 如何从主要活动中调用 onDraw 方法?我可能需要在 onDraw() 方法中传递颜色参数
    • @Erum Hannan 你不调用 onDraw,但这不是讨论的地方。请参阅 Activity 的文档。
    猜你喜欢
    • 1970-01-01
    • 2011-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    相关资源
    最近更新 更多