Different ways to create glowing shapes in Android canvas.

Yuriy Skul
4 min readJul 7, 2020

--

What if you have to implement glowing in android. There are different ways how it can be done. In this article let’s implement it in some different ways.
This is just a starter code for analysis and comparison of these ways…


Starter code

For article I have taken the idea of drawing ring shapes. I am not going to handle positions in landscape and extracting ring’s parameters from constructor.

Three rings have same x position.
Middle ring is going to be centered vertically.
Top and bottom rings are equidistant to the middle ring border and top/bottom view edges.
So initialize these variables in onSizeChanged():

Now it’s time to draw rings:

BlurMaskFilter ring

Main idea is to use two ring shapes — one is for body with body color and another is for glowing. Body ring has to be drawn on top of the glowing.

Define method initBlurPainting(Canvas canvas). It initializes paint objects for drawing glowing ring and simple ring on top of it.
Call this method from init():

Method setMaskFilter(newBlurMaskFilter(...)) does the main glowing “magic”.

And call from onDraw() method which draws glowing ring body and body ring on top:

That is all. Resulting ring:

Using paint with BlurMask filter

ShadowLayer ring

For current way we don’t need two different shapes for glowing and body.
Just one shape.
Main trick is to set to the paint object shadow layer: paint.setShadowLayer(...)

Define the method which initializes paint for drawing ring and cal it from init() method:

I have used radius = blurRadiusPx * 2 just for making shadowLayer ring look more like previous ring.

I have used body color for shadow layer too because making it transparent will be handled automatically. It looks like shadow layer alpha of color is close to 20–23%.

And now just use this shadowLayerPaint object for drawing circle from onDraw():

Ring with shadow layer paint

RadialGradient shader Ring

Main idea is to define and use paint with RadialGradient shader.
Update init() with:

No need to set color to the paint — shader is going to handle coloring, but for instantiation RaidalGradient object we need to know center X and center Y.
It can be done in onSizeChanged(…) method:

createRadialGradient() method’s body looks complicated but the main idea is to define array with of normalized path of points where color is defined. It goes from center position up to the end of the ring outer shape and define coincident array of colors, each color of array is associated with its path point from points array.
The center of ring shape is transparent and it is going up to the
inner contour of shape and it is here still transparent; here gradual change of color starts by increasing path radius and keeps changing up to the value of glowingColor; then it keeps constantly this color value for some distance: glowStrokeWidthPx / 4-bodyStrokeWidthPx / 2 and then it changes abruptly to the bodyColor; next distance keeps constant body color and then everything goes in revers symmetrical way:

Now call drawing this ring from onDraw():

The bottom ring is this one and it looks like others:

Ring with radial gradient shader

And the whole screen:

All those rings look very similar.
If we initialize private int glowingColor variable with GLOW_COLOR_80P_ALPHA instead of GLOW_COLOR_20P_ALPHA the output will be exactly like the top image in the header of this article.

But which way has less CPU usage…
Paint with RadialGradient is bound to the specific center point but what if we need to run animation that changes shape’s radius or position…Recreating shader object on every call onDraw() is definitely not a good idea…Of course we can translate and scale canvas.
Paint with shadow layer is intended for drawing shadows but not for glowing and if we want glowing color to be more saturated and toxic — there is no simple public method to change shadow layer color.
Paint with BlurMaskFilter will have weird visual result when we have to use hardware accelerated drawing model because paint.setMaskFilter()method is not supported for this drawing model.

Thanx for reading)

Solution code:

--

--