We’ve had gradient support in VectorDrawable since API 24 and I have written about them previously. In those articles I covered an problem importing sweep gradients because sweep gradients are not supported in SVG, which is a failing of SVG rather than any Android specifics. However there is another edge case which is supported in SVG but the Asset Studio tool in Android Studio does not handle, but with a bit of understanding we can manually implement. I was first asked about this by a designer based in Sweden named Olga Zhernova and I made a brief suggestion of what is to follow and she was able to achieve what she wanted. So thanks to Olga for asking an interesting question! In this post we’ll take a look at the issue and see how we can it.

- Elliptical - Elliptical Vector Gradients – Styling AndroidThe image to the left shows a specific kind of radial gradient – rather than the bounds of the gradient being circular, the width and height are different resulting in an shape to the gradient which starts at white, and transitions to green. In some graphic design tools it is possible to create these gradients, and I was able to create one in Sketch. The gradient tool in Sketch perfectly shows this shape:

- sketch gradient - Elliptical Vector Gradients – Styling Android

If I export this to an SVG we can open it in Chrome and the elliptical gradient is still there:

- chrome2 - Elliptical Vector Gradients – Styling Android

If I now import this in to Android Studio using Vector Studio, then even in the preview of the VectorDrawable before we complete the import we can see that the elliptical shape has been lost and we revert to a standard circular radial gradient:

- AssetStudio2 - Elliptical Vector Gradients – Styling Android

The reason for this may seem obvious to those familiar with RadialGradient in Android which is used when rendering gradients directly to a Canvas, and is the basis for the radial gradient in VectorDrawable. RadialGradient only permits us to specify a single value as the radius of the gradient meaning that it will only render circular gradients.

At first glance this may appear to be fairly insurmountable – if RadialGradient does not support asymmetric gradients then it makes sense that Asset Studio cannot handle them on import. However, just because RadialGradient only supports symmetrical gradients does not mean that we cannot render them. Canvas allows us to apply independent X and Y scaling and if we do apply different X and Y scale factors prior to rendering using the RadialGradient shader, then we can effectively render an asymmetric radial gradient.

We can also apply this same principle to VectorDrawable to get an asymmetric radial gradient by applying the scale by using a group. To understand how to do this, let’s first take a look at the VectorDrawable which I imported from SVG (which lost the elliptical gradient):

I should mention that I slightly tweaked the path datafrom what was imported because it will hopefully make what follows a little easier to follow. The original path was M50,50m-45,0a45,45 0,1 1,90 0a45,45 0,1 1,-90 0 and I converted it to a single arc rather than two semicircular arcs: M50,5 a45,45 0 1 0 0.1,0 z

Anyone familiar with using radial gradients within VectorDrawable should have an idea of how this will look, and that it will have a symmetrical, circular radial gradient – which ties in with the preview:

- symmetrical - Elliptical Vector Gradients – Styling Android

We now wrap this inside a group with scaleY="2" and then tweak the centreY and gradientRadius attributes by halving each of them to compensate for the Y scaling added to the group:

This now looks like this:

- elliptical1 - Elliptical Vector Gradients – Styling Android

So we now have an elliptical gradient, but we have also distorted the circular outline, which is not what we wanted. One solution would be to change the path itself to fill a rectangle, and then apply a clip-path before, and outside of the group:

At a first glance this looks fine:

- elliptical2 - Elliptical Vector Gradients – Styling Android

However, if you look carefully at the edges of the circle they are quite jagged. This is because clip-path renders at pixel level meaning that it controls whether a given pixel can be painted or not. A path on the other hand, renders at a sub-pixel level meaning that for a pixel on the perimeter of the circle, the actual colour that it is painted will be determined by the proportion of that pixel which falls inside the circle. This is known as anti-aliasing and results in edges which appear much smoother to the human eye. It’s the lack of this anti-aliasing (which we lose with clip-path) which causes these jaggies.

In order to get rid of the jaggies, a better solution is to actually tweak the path data of the circle to account for the change to the Y scaling. In this case the Y component of the move command needs halving from M50,5 to M50,2.5 and the radius of the arc needs halving from a45,45 0 1 0 0.1,0 to a45,22.5 0 1 0 0.1,0:

It now looks like this:

- elliptical3 - Elliptical Vector Gradients – Styling Android

So we now have an elliptical gradient, inside a symmetrical circle, with no jaggies!

So we can manually implement an asymmetric radial gradient by using an asymmetrical scaling in a group,. and then manually tweaking the gradient and path data parameters to compensate for that scaling.

Once again, my thanks to Olga Zhernova for asking the question which prompted this post.

The source code for this article is available here.

© , Mark Allison. All rights reserved.

CC BY-NC-SA 4.0  - 88x31 - Elliptical Vector Gradients – Styling Android
Elliptical Vector Gradients by Styling Android is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Permissions beyond the scope of this license may be available at

Source link


Please enter your comment!
Please enter your name here