Android自定义视图无法以正确的方式处理透明度/ alpha

EGH*_*HDK 8 java android alpha android-custom-view

我正在绘制自定义视图.在此视图中,我使用两个不同的绘制和路径对象绘制到画布.我基本上画了两个重叠的形状.添加alpha后,视图中重叠的部分比图像的其余部分更暗.这是不受欢迎的,但我不确定如何解决它.

这是我的代码的剪辑,以显示我如何在我的NewButtonView.java中使用alpha

Paint paint = new Paint();
int color = 0x33ffffff;
int borderColor = 0xFF000000;

paint.setColor(color);
paint.setAntiAlias(true);
paint.setStrokeWidth(strokeWidth);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.FILL);
Run Code Online (Sandbox Code Playgroud)

这个Google I/O视频大约需要31分钟......它们会显示我想要的效果.

他们基本上显示这个图像: 在此输入图像描述

添加透明度并获取此图像:UNDESIRED RESULT

在此输入图像描述

他们最终得到了这个:渴望的结果

在此输入图像描述

有没有人知道如何获得这种理想的效果?

Vik*_*ram 12

如视频中所述,您可以使用Canvas#saveLayerAlpha(....)此功能.您也可以在不使用它的情况下获得类似的效果.我稍后会讨论这个问题.

让我们创建一个示例视图:

public class SampleView extends View {

    // Declare Paint objects
    Paint paintColor, paintBorder;

    public SampleView(Context context) {
        super(context);

        // Initialize and set up Paint objects
        paintColor = new Paint();
        paintBorder = new Paint();

        paintColor.setAntiAlias(true);
        paintBorder.setAntiAlias(true);

        paintBorder.setColor(Color.BLACK);
        paintBorder.setStyle(Style.STROKE);
        paintBorder.setStrokeWidth(10);

        // Just a random image to 'see' the difference
        setBackground(getResources().getDrawable(R.drawable.hor_lines));
    }

    @Override 
    protected void onDraw(Canvas canvas) {

        // Save layer alpha for Rect that covers the view : alpha is 90 / 255
        canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 90, 
                                             Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);

        // Draw first circle, and then the border
        paintColor.setColor(Color.RED);
        canvas.drawCircle(getWidth() / 3, getHeight() / 2, 
                                           getWidth() / 4 - 20, paintColor);

        canvas.drawCircle(getWidth() / 3, getHeight() / 2, 
                                           getWidth() / 4 - 15, paintBorder);

        // Draw second circle, and then the border
        paintColor.setColor(Color.BLUE);
        canvas.drawCircle(2 * getWidth() / 3, getHeight() / 2, 
                                           getWidth() / 4 - 20, paintColor);
        canvas.drawCircle(2 * getWidth() / 3, getHeight() / 2, 
                                           getWidth() / 4 - 15, paintBorder);

        // Finally, restore the canvas
        canvas.restore();
    }
}
Run Code Online (Sandbox Code Playgroud)

怎么了:

  1. saveLayerAlpha(....)调用时会分配屏幕外位图.

  2. 所有绘图操作都发生在此位图上.

  3. canvas.restore()被调用时,这个位图被转移到屏幕上的画布,我们提供在阿尔法值saveLayerAlpha(....)被施加到屏幕外位图.

(我认为)以下是在不使用以下情况下创建此效果的等效方法saveLayerAlpha(....):

public class SView extends View {

    Paint paintColor, paintBorder, paintAlpha;

    Bitmap toDrawOn;

    public SView(Context context) {
        super(context);

        paintAlpha = new Paint();

        paintAlpha.setColor(Color.parseColor("#90FFFFFF"));
        paintAlpha.setAntiAlias(true);

        ....
        ....

    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (toDrawOn == null) {

            // Create a new Bitmap
            toDrawOn = Bitmap.createBitmap(getWidth(), getHeight(), 
                                                    Config.ARGB_8888);

            // Create a new Canvas; drawing operations 
            // will happen on 'toDrawOn'
            Canvas offScreen = new Canvas(toDrawOn);

            // First circle
            paintColor.setColor(Color.RED);
            offScreenCanvas.drawCircle(getWidth() / 3, getHeight() / 2, 
                                           getWidth() / 4 - 20, paintColor);
            offScreenCanvas.drawCircle(getWidth() / 3, getHeight() / 2, 
                                           getWidth() / 4 - 15, paintBorder);

            // Second circle
            paintColor.setColor(Color.BLUE);
            offScreenCanvas.drawCircle(2 * getWidth() / 3, getHeight() / 2, 
                                           getWidth() / 4 - 20, paintColor);
            offScreenCanvas.drawCircle(2 * getWidth() / 3, getHeight() / 2, 
                                           getWidth() / 4 - 15, paintBorder);

            // Draw bitmap 'toDrawOn' to canvas using 'paintAlpha'
            canvas.drawBitmap(toDrawOn, 0, 0, paintAlpha);

        } else {

            // 'toDrawOn' is not null; draw it
            canvas.drawBitmap(toDrawOn, 0, 0, paintAlpha);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

在此输入图像描述

仅供参考,上图中的基本容器是LinearLayout背景设置为此jpeg:Link.

并且,drawable用作SampleView的背景:

// Just a random image to 'see' the difference
setBackground(getResources().getDrawable(R.drawable.hor_lines));
Run Code Online (Sandbox Code Playgroud)

取自:这里.

  • 请注意,docs建议对View而不是saveLayer*方法使用硬件层. (2认同)