Recently there was a comment on the article on Text Shadows asking how to fill text with a gradient. In this article we’ll look at a simple technique for doing precisely that.
Creating text filled with a gradient is actually really easy, although it’s not immediately obvious how to do it in the same was as simply changing the text colour. The trick is to use a Shader, or more specifically a LinearGradient (which extends Shader), to do all of the work for us.
The constructor for LinearGradient that we’ll use takes seven arguments, although there is also a more complex form which allows for multiple colour steps to be defined. The first four of these represent the start x & y and end x & y coordinates of the line along which the gradient will be drawn (this effectively controls the direction of the gradient). The next two arguments represent the start and end colours of the gradient, and the final argument dictates how areas outside of the rectangle defined in the first four arguments will be drawn.
So how do we go about applying this? In its simplest form, we can get a reference to a standard TextView object, and set the Shader on it’s Paint object:
Shader myShader = new LinearGradient(
0, 0, 0, 100,
textview.getPaint().setShader( myShader );
The TileMode that we’re using means that the colour of areas outside of the rectangle (0, 0) – (0, 100) will match the colour of the closest edge of that rectangle – i.e. extending the colour of the edges of the rectangle.
While this will certainly work, it does suffer from the small drawback that the gradient will need to be static dimensions which are completely detached from the size of the text within the TextView. So what if we want the dimensions of the gradient to actually match our text? We simply need to extend TextView.
Now the obvious thought is to extend TextView and simply override
onDraw() to create a new LinearGradient which matches the dimensions of the textView control each time the control is drawn. However this is rather inefficient because it means instantiating a Shader object each time onDraw is called. Object instantiation is a rather expensive business and should be avoided at all costs in your onDraw method. If you perform object instantiation in your onDraw you’ll find that your frame rates suffer badly as a result.
So if we don’t do it in onDraw, then where should we do it? The answer is quite obvious when we think about how often we actually need to create a new LinearGradient: only when the size of the TextView changes. Therefore, the most efficient place to do this is actually in onLayout:
public class GradientTextView extends TextView
public GradientTextView( Context context )
super( context, null, -1 );
public GradientTextView( Context context,
AttributeSet attrs )
super( context, attrs, -1 );
public GradientTextView( Context context,
AttributeSet attrs, int defStyle )
super( context, attrs, defStyle );
protected void onLayout( boolean changed,
int left, int top, int right, int bottom )
super.onLayout( changed, left, top, right, bottom );
getPaint().setShader( new LinearGradient(
0, 0, 0, getHeight(),
Shader.TileMode.CLAMP ) );
So, whenever the layout changes we create and set a new LinearGradient based on the height of the TextView.
Running this gives us the following:
This same technique can be used to apply different kinds of gradients (LinearGradient, RadialGradient, SweepGradient), filling text with a bitmap (BitmapShader), or even combining shaders (ComposeShader). The more adventurous can even create their own custom shaders!
While we’ve only covered a really simple example here, we have covered a very useful technique which is pretty easy to implement, and can give us some impressive results.
The source code for this article is available here.
© 2013 – 2014, Mark Allison. All rights reserved. This article originally appeared on Styling Android.
Portions of this page are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License
Gradient Text by Styling Android, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Terms and conditions beyond the scope of this license may be available at blog.stylingandroid.com.