Michalsx
Michalsx

Reputation: 3621

How to set gradient on TextView color with angle?

Following code will set gradient on textview (not background, but text itself). But I need to change angle of this gradient, how to do it?

Shader textShader = new LinearGradient(0, 0, 0, textView.getPaint().getTextSize(),
        new int[]{context.getResources().getColor(R.color.color1), context.getResources().getColor(R.color.color2)},
        new float[]{0, 1}, Shader.TileMode.CLAMP);
textView.getPaint().setShader(textShader);

Thank you in advance.

Upvotes: 6

Views: 3647

Answers (3)

Mir Milad Hosseiny
Mir Milad Hosseiny

Reputation: 2857

According to this answer, I modified your code. Try this:

double angleInRadians = Math.toRadians(45);
double length = textView.getPaint().getTextSize();

double endX = Math.sin(angleInRadians) * length;
double endY = Math.cos(angleInRadians) * length;

Shader textShader = new LinearGradient(0, 0, endX, endY,
        new int[]{context.getResources().getColor(R.color.color1), context.getResources().getColor(R.color.color2)},
        new float[]{0, 1}, Shader.TileMode.CLAMP);
textView.getPaint().setShader(textShader);


Update:
I'm ashamed to say that my above answer is not correct. These answers (mayank1513 answer and Chaudhari Sachin answer) are the same and they are good but they have few bugs:
1. They don't work correctly for agnles more than 90 degrees. For exmaple if you test them with 180 degrees, then you won't see any gradient, because these solutions are using (0,0) point as rotation center.
2. If you have a TextView with width or height more or less than its text width or height, then gradient doesn't render correctly. For example you can test it by a TextView with match_parent width and height and centered Hello text or with an enabled scrolling small TextView and long text.
I developed new soltuion. It calcuates text bound first and then rotates gradient line around center of this bound.

textView.post(new Runnable() {
    @Override
    public void run() {

        final Rect textBound = new Rect(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);

        final Layout layout = textView.getLayout();
        for(int i = 0; i < textView.getLineCount(); i++) {
            float left = layout.getLineLeft(i);
            float right = layout.getLineRight(i);
            if(left < textBound.left) textBound.left = (int)left;
            if(right > textBound.right) textBound.right = (int)right;
        }
        textBound.top = layout.getLineTop(0);
        textBound.bottom = layout.getLineBottom(textView.getLineCount() - 1);
        if(textView.getIncludeFontPadding()) {
            Paint.FontMetrics fontMetrics = textView.getPaint().getFontMetrics();
            textBound.top += (fontMetrics.ascent - fontMetrics.top);
            textBound.bottom -= (fontMetrics.bottom - fontMetrics.descent);
        }

        double angleInRadians = Math.toRadians(45);

        double r = Math.sqrt(Math.pow(textBound.bottom - textBound.top, 2) +
                Math.pow(textBound.right - textBound.left, 2)) / 2;

        float centerX = textBound.left + (textBound.right - textBound.left) / 2;
        float centerY = textBound.top + (textBound.bottom - textBound.top) / 2;

        float startX = (float)Math.max(textBound.left, Math.min(textBound.right, centerX - r * Math.cos(angleInRadians)));
        float startY = (float)Math.min(textBound.bottom, Math.max(textBound.top, centerY - r * Math.sin(angleInRadians)));

        float endX = (float)Math.max(textBound.left, Math.min(textBound.right, centerX + r * Math.cos(angleInRadians)));
        float endY = (float)Math.min(textBound.bottom, Math.max(textBound.top, centerY + r * Math.sin(angleInRadians)));

        Shader textShader = new LinearGradient(startX, startY, endX, endY,
                new int[]{context.getResources().getColor(R.color.color1),
                        context.getResources().getColor(R.color.color2)},
                new float[]{0, 1}, Shader.TileMode.CLAMP);

        textView.setTextColor(Color.WHITE);
        textView.getPaint().setShader(textShader);
    }
});

Upvotes: 2

Chaudhari Sachin
Chaudhari Sachin

Reputation: 71

final TextView myTextView = findViewById(R.id.my_text_view);

myTextView.post(new Runnable() 
    {

         @Override

            public void run() {

                int length = textView.getMeasuredWidth();

            float angle = 45; // specify angle in degrees here

            Shader textShader = new LinearGradient(0, 0, (int) (Math.sin(Math.PI * angle / 180) * length), 
                                    (int) (Math.cos(Math.PI * angle / 180) * length),

                                        new int[]{Color.BLUE, Color.GREEN, Color.GREEN, Color.BLUE, Color.RED, Color.GREEN, Color.BLUE, Color.RED},

    null, 
        Shader.TileMode.CLAMP);

        myTextView.getPaint().setShader(textShader);

            textView.invalidate();

            }

    });

result

Upvotes: 2

Mayank Kumar Chaudhari
Mayank Kumar Chaudhari

Reputation: 18538

Working code

final double angleInRadians = Math.toRadians(45);
final TextView textView = findViewById(R.id.app_name);
    textView.post(new Runnable() {
        @Override
        public void run() {
            double length = textView.getMeasuredWidth();

            double endX = Math.sin(angleInRadians) * length;
            double endY = Math.cos(angleInRadians) * length;

            Shader textShader = new LinearGradient(0, 0, (int) endX, (int) endY,
                    new int[]{Color.BLUE, Color.GREEN, Color.GREEN, Color.BLUE, Color.RED, Color.GREEN, Color.BLUE, Color.RED},
                    null, Shader.TileMode.CLAMP);
            textView.getPaint().setShader(textShader);
            textView.invalidate();
        }
    });

This sets gradient with specified angle.

Upvotes: 1

Related Questions