Android Gradient Text

How do I expand a TextView to allow drawing text with a gradient effect?

+55
android user-interface
Apr 21 2018-10-10T00:
source share
8 answers

It is not possible to extend a TextView to draw text using a gradient. However, this effect can be achieved by creating a canvas and drawing on it. First we need to declare our user interface element . First we need to create a subclass of Layout . In this case, we will use BoringLayout , which only supports single-line text.

 Shader textShader=new LinearGradient(0, 0, 0, 20, new int[]{bottom,top}, new float[]{0, 1}, TileMode.CLAMP);//Assumes bottom and top are colors defined above textPaint.setTextSize(textSize); textPaint.setShader(textShader); BoringLayout.Metrics boringMetrics=BoringLayout.isBoring(text, textPaint); boringLayout=new BoringLayout(text, textPaint, 0, Layout.Alignment.ALIGN_CENTER, 0.0f, 0.0f, boringMetrics, false); 

Then we override onMeasure and onDraw :

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ setMeasuredDimension((int) textPaint.measureText(text), (int) textPaint.getFontSpacing()); } @Override protected void onDraw(Canvas canvas){ super.onDraw(canvas); boringLayout.draw(canvas); } 

Our onDraw implementation is currently pretty lazy (it completely ignores the measurement specifications!, But as long as you guarantee that the view is given enough space, it should work fine.

Alternatively, you could inherit from Canvas and override the onPaint method. If this is done, then, unfortunately, the anchor for the drawn text will always be down, so we must add -textPaint.getFontMetricsInt().ascent() to our y coordinate.

+19
Apr 27 '10 at 5:30
source share
 TextView secondTextView = new TextView(this); Shader textShader=new LinearGradient(0, 0, 0, 20, new int[]{Color.GREEN,Color.BLUE}, new float[]{0, 1}, TileMode.CLAMP); secondTextView.getPaint().setShader(textShader); 
+122
Feb 23 2018-11-11T00:
source share

I used the top answer (@Taras) with a gradient of 5 colors, but there is a problem: the textView looks like I put a white cover on it. Here is my code and screenshot.

  textView = (TextView) findViewById(R.id.main_tv); textView.setText("Tianjin, China".toUpperCase()); TextPaint paint = textView.getPaint(); float width = paint.measureText("Tianjin, China"); Shader textShader = new LinearGradient(0, 0, width, textView.getTextSize(), new int[]{ Color.parseColor("#F97C3C"), Color.parseColor("#FDB54E"), Color.parseColor("#64B678"), Color.parseColor("#478AEA"), Color.parseColor("#8446CC"), }, null, Shader.TileMode.CLAMP); textView.getPaint().setShader(textShader); 

enter image description here

After many hours, I found that I needed to call textView.setTextColor() with the first color of the gradient. Then a screenshot:

enter image description here

Hope to help someone!

+14
Sep 12 '18 at 7:41
source share

I rolled up a library that covers both of these methods. You can create a GradientTextView in XML or just use GradientTextView.setGradient (TextView textView ...) to do this on a regular TextView object.

https://github.com/koush/Widgets

+10
Jun 18 2018-11-11T00:
source share

Here it is, with support for multiple lines as a single liner. This should work for buttons as well.

 Shader shader = new LinearGradient(0,0,0,textView.getLineHeight(), startColor, endColor, Shader.TileMode.REPEAT); textView.getPaint().setShader(shader); 
+9
Feb 26 '16 at 22:45
source share

A simple but somewhat limited solution would be to use these attributes:

 android:fadingEdge="horizontal" android:scrollHorizontally="true" 

I used it on text boxes where I want them to disappear if they are too long.

+3
Apr 21 '10 at 8:14
source share

Here is a good way to do this:

 /** * sets a vertical gradient on the textView paint, so that on its onDraw method, it will use it. * * @param viewAlreadyHasSize * set to true only if the textView already has a size */ public static void setVerticalGradientOnTextView(final TextView tv, final int positionsAndColorsResId, final boolean viewAlreadyHasSize) { final String[] positionsAndColors = tv.getContext().getResources().getStringArray(positionsAndColorsResId); final int[] colors = new int[positionsAndColors.length]; float[] positions = new float[positionsAndColors.length]; for (int i = 0; i < positionsAndColors.length; ++i) { final String positionAndColors = positionsAndColors[i]; final int delimeterPos = positionAndColors.lastIndexOf(':'); if (delimeterPos == -1 || positions == null) { positions = null; colors[i] = Color.parseColor(positionAndColors); } else { positions[i] = Float.parseFloat(positionAndColors.substring(0, delimeterPos)); String colorStr = positionAndColors.substring(delimeterPos + 1); if (colorStr.startsWith("0x")) colorStr = '#' + colorStr.substring(2); else if (!colorStr.startsWith("#")) colorStr = '#' + colorStr; colors[i] = Color.parseColor(colorStr); } } setVerticalGradientOnTextView(tv, colors, positions, viewAlreadyHasSize); } /** * sets a vertical gradient on the textView paint, so that on its onDraw method, it will use it. <br/> * * @param colors * the colors to use. at least one should exist. * @param tv * the textView to set the gradient on it * @param positions * where to put each color (fraction, max is 1). if null, colors are spread evenly . * @param viewAlreadyHasSize * set to true only if the textView already has a size */ public static void setVerticalGradientOnTextView(final TextView tv, final int[] colors, final float[] positions, final boolean viewAlreadyHasSize) { final Runnable runnable = new Runnable() { @Override public void run() { final TileMode tile_mode = TileMode.CLAMP; final int height = tv.getHeight(); final LinearGradient lin_grad = new LinearGradient(0, 0, 0, height, colors, positions, tile_mode); final Shader shader_gradient = lin_grad; tv.getPaint().setShader(shader_gradient); } }; if (viewAlreadyHasSize) runnable.run(); else runJustBeforeBeingDrawn(tv, runnable); } public static void runJustBeforeBeingDrawn(final View view, final Runnable runnable) { final OnPreDrawListener preDrawListener = new OnPreDrawListener() { @Override public boolean onPreDraw() { view.getViewTreeObserver().removeOnPreDrawListener(this); runnable.run(); return true; } }; view.getViewTreeObserver().addOnPreDrawListener(preDrawListener); } 

Also, if you want to use a gradient bitmap instead of a real one, use:

 /** * sets an image for the textView <br/> * NOTE: this function must be called after you have the view have its height figured out <br/> */ public static void setBitmapOnTextView(final TextView tv, final Bitmap bitmap) { final TileMode tile_mode = TileMode.CLAMP; final int height = tv.getHeight(); final int width = tv.getWidth(); final Bitmap temp = Bitmap.createScaledBitmap(bitmap, width, height, true); final BitmapShader bitmapShader = new BitmapShader(temp, tile_mode, tile_mode); tv.getPaint().setShader(bitmapShader); } 

EDIT: Alternative to runJustBeforeBeingDrawn: https://stackoverflow.com/questions/35172/ ...

+1
Jul 09 '15 at 8:03
source share

Here is an example for linearlayout, you can also use this example for text viewing, and there will be no gradient coding in the source code, you get the source code and add the code from this site - http://android-codes-examples.blogspot.com/2011 /07/design-linearlayout-or-textview-and-any.html

0
Jul 12 '11 at 5:23
source share



All Articles