3

Currently, I have an app which support Android 2.3 and above.

In my custom view drawing operation, I need to drop shadow while drawing circle.

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

I also understand that, with hardware acceleration turned on, I will not such shadow effect

setShadowLayer Android API differences

However, I realize once hardware acceleration is turned off through view.setLayerType(View.LAYER_TYPE_SOFTWARE, null), my entire custom view drawing operation become very slow.

I was wondering, is there any other way to achieve similar shadow effect. (A "blurred" black circle shadow)

enter image description here

without turning off hardware acceleration?

p/s Even when I want to use BlurMaskFilter from Android draw with blur, I realize it doesn't support hardware acceleration too.

Community
  • 1
  • 1
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875

1 Answers1

2

I had found a way to achieve such. First, we construct the ball + shadow off-screen image. Note, by using off-screen bitmap drawing technique, no GPU will be involved. The key is, don't use the Canvas from onDraw to perform drawCircle.

Instead, construct our very own Canvas, backed by an 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 function, just draw the off-screen bitmap directly.

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

For the entire process, I merely depend on the default value of layer type, without calling setLayerType explicitly.

The outcome is fast, yet shadow effect is visible too.

Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875
  • would you explain this lint " Bitmap bitmap = Bitmap.createBitmap((int)((ballSize + ballShadowSize)*2f), (int)((ballSize + ballShadowSize)*2f), Bitmap.Config.ARGB_8888); " – MohammedAlSafwan Jan 21 '17 at 18:04