Text with gradient in Android

Solution 1:

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);

Solution 2:

I have used the top answer(@Taras) with a gradient of 5 colors, but there is a problem: the textView looks like that I have put a white cover on it. Here is my code and the 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 out that I need to call textView.setTextColor() with the first color of the gradient. Then the screenshot:

enter image description here

Hope help someone!

Solution 3:

It doesn't appear possible to extend TextView to draw text with a gradient. It is, however, possible to achieve this effect by creating a canvas and drawing on it. First we need to declare our custom UI element. In the initiation we need to create a subclass of Layout. In this case, we will use BoringLayout which only supports text with a single line.

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);

We then 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 implementation of onDraw is at this point quite lazy (it completely ignores the measurement specs!, but so long as you guarantee that the view is given sufficent space, it should work okay.

Alternatively, it would be possible to inherit from a Canvas and override the onPaint method. If this is done, then unfortunately the anchor for text being drawn will always be on the bottom so we have to add -textPaint.getFontMetricsInt().ascent() to our y coordinate.