我正在绘制自定义 View 。在此 View 中,我使用两个不同的绘制对象和路径对象将其绘制到 Canvas 上。我基本上是在画两个重叠的形状。添加Alpha后,重叠的 View 部分比图像的其余部分更暗。这是不希望的,但我不确定如何解决。

这是我的代码的一部分,以显示我如何在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);

进入Google I/O video大约31分钟...它们显示了我想要的效果。

他们基本上显示此图像:

添加透明度并获得此图像:不需要的结果

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

有谁知道如何获得这种期望的影响?

最佳答案

如视频中所提到的,您将为此使用Canvas#saveLayerAlpha(....)。您也可以不使用它而获得类似的效果。稍后再讨论。

让我们创建一个示例 View :

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();
    }
}

怎么了:
  • 调用saveLayerAlpha(....)时分配了屏幕外位图。
  • 所有绘制操作都在此位图上进行。
  • 调用canvas.restore()时,此位图将传输到屏幕上的 Canvas ,我们在saveLayerAlpha(....)中提供的alpha值将应用于屏幕外的位图。

  • (我认为)以下是在不使用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);
            }
        }
    }
    

    输出:

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

    并且,将drawable用作SampleView的背景:
    // Just a random image to 'see' the difference
    setBackground(getResources().getDrawable(R.drawable.hor_lines));
    

    取自:here

    09-28 01:07