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)
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.
source to share
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.
source to share