如何在TextView上设置带有角度的渐变颜色?

6
以下代码将在TextView上设置渐变(不是背景,而是文本本身)。但我需要更改此渐变的角度,如何操作?
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);

谢谢您的提前帮助。
3个回答

2
根据这个答案,我修改了您的代码。请尝试以下代码:
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);


更新:
我很惭愧地说,我的上面的回答是不正确的。这些答案(mayank1513 answerChaudhari Sachin answer)是相同的,它们很好,但它们有一些错误:
1. 它们对于大于90度的角度不正确。例如,如果你用180度测试它们,那么你将看不到任何渐变,因为这些解决方案使用(0,0)点作为旋转中心。
2. 如果你有一个TextView的宽度或高度比其文本宽度或高度更多或更少,那么渐变不会正确地呈现。例如,你可以通过一个具有match_parent宽度和高度和居中Hello文本或启用滚动小TextView和长文本来测试它。
我开发了新的解决方案。它首先计算文本范围,然后围绕该范围的中心旋转渐变线。

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

渐变只出现在第一个字符上 - 其他字符是单色的。 - Mayank Kumar Chaudhari
这个答案基于你的代码,我使用了new float[] {0, 1}作为Positions参数。你可以使用null来使它线性。根据官方文档: "float: 可以为空。颜色数组中每个对应颜色的相对位置 [0..1]。如果这是空的,那么颜色沿着渐变线均匀分布。此值可以为空。" - Mir Milad Hosseiny
float[] 不是问题。问题在于测量文本宽度。 - Mayank Kumar Chaudhari
1
它提供文本高度而不是宽度 --- 渐变跨度仅限于第一个字符。 - Mayank Kumar Chaudhari

2
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


来自评论区:嗨,请不要只回复源代码,尝试提供一个关于你的解决方案如何工作的好描述。参见:如何撰写好的答案?。谢谢。 - sɐunıɔןɐqɐp

1

工作中的代码

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

这将使用指定的角度设置渐变。


为什么要使用Runnable并发布它?您可以在没有Runnable的情况下进行更改。此外,您不需要使textview无效。 - Mir Milad Hosseiny
1
如果不使用post,测量宽度为零 - 在onCreate中使用它 - Mayank Kumar Chaudhari
1
如果使用“posr”,则必须使其无效,否则更改将不会显示。 - Mayank Kumar Chaudhari
endX + endYY 总是等于 0。 - famfamfam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接