Achieve setShadowLayer effect during drawCircle (or drawRoundRect) without disabling hardware acceleration

I currently have an app that supports Android 2.3 and above.

In my custom view draw operation, I need to cast a shadow while drawing a circle.

ballPaint.setShadowLayer(shadowSize, shadowSize, shadowSize, historyChartBallShadow);
canvas.drawCircle(px, py, this.ballSize, ballPaint);

      

I also understand that with hardware acceleration enabled I will not use shadow effect

differences in AndroidShadowLayer API

However, I understand that after hardware acceleration is disabled via view.setLayerType(View.LAYER_TYPE_SOFTWARE, null)

, my entire custom drawing views operation becomes very slow.

I was wondering if there is another way to achieve a similar shadow effect. ("Blurred" shadow of a black circle)

enter image description here

without disabling hardware acceleration?

p / s Even if I want to use BlurMaskFilter

from Android draw with blur , I understand that it also doesn't support hardware acceleration.

+3


source to share


1 answer


I found a way to achieve this. First, we create a ball + shadow onscreen. Note that with the screenless bitmap stripping technology, the GPU will not be involved. Key: don't use Canvas

from onDraw

for execution drawCircle

.

Instead, create our own Canvas

, supported off-screen bitmap.

private Bitmap generateBallBitmap() {
    final int ballShadowSize = Utils.dpToPixel(BALL_SHADOW_SIZE);

    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setColor(historyChartBallColor);
    paint.setShadowLayer(ballShadowSize, ballShadowSize, ballShadowSize, historyChartBallShadow);

    Bitmap bitmap = Bitmap.createBitmap((int)((ballSize + ballShadowSize)*2f), (int)((ballSize + ballShadowSize)*2f), Bitmap.Config.ARGB_8888);
    bitmap.eraseColor(Color.TRANSPARENT);
    Canvas canvas = new Canvas(bitmap);
    canvas.drawCircle(ballSize, ballSize, ballSize, paint);

    return bitmap;
}

      

In custom view, onDraw

just capture the bitmap off-screen.



if (null == this.ballBitmap) {
    this.ballBitmap = generateBallBitmap();
}
canvas.drawBitmap(this.ballBitmap, px - this.ballSize, py, null);

      

For the whole process, I just rely on the default of the layer type without calling explicitly setLayerType

.

The result is quick, but the shadow effect is also visible.

+2


source







All Articles