实现TextView文本颜色渐变的骚操做

前言

最近开发过程当中要实现文本颜色渐变的效果。什么,文本颜色也要渐变?虽然不乐意,可是也只能说好吧...java

先来点最终效果图 android

在这里插入图片描述
在这里插入图片描述

常规操做

常见的渐变作法有两种,原理其实都是同样的。都是建立一个 LinearGradient 对象,并将其设置到 TextView 的画笔中。app

先来简单介绍下 LinearGradientide

LinearGradient

Shader 子类,用于实现线性渐变的效果。经常使用的构造方法以下测试

public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile) 复制代码

参数说明ui

  • (x0, y0):渐变起始点坐标
  • (x1, y1):渐变结束点坐标
  • color0:渐变起始颜色
  • color1:渐变终止颜色
  • tile:填充模式
    • CLAMP:边缘拉伸。使用边缘颜色对区域外的范围进行填充
    • REPEAT:重复模式。在水平和垂直两个方向上重复填充
    • MIRROR:镜像模式。在水平和垂直两个方向上以镜像的方式重复填充,相邻图像间有间隙

作法一

继承 TextView,重写 onLayout 方法后设置 Shaderthis

public class GradientTextView extends TextView {
	...
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) {
            getPaint().setShader(new LinearGradient(0, 0, getWidth(), getHeight(),
                    startColor,
                    endColor,
                    Shader.TileMode.CLAMP));
        }
    }
}
复制代码

建立 LinearGradient 时,传入的起始坐标为 (0,0),结束坐标为 (getWidth(), getHeight()),因此渐变效果是从左上角向右下角渐变的。效果以下 spa

在这里插入图片描述
也能够改为从上往下渐变的效果

getPaint().setShader(new LinearGradient(0, 0, 0, getHeight(),
                    startColor,
                    endColor,
                    Shader.TileMode.CLAMP));
复制代码

效果以下 3d

在这里插入图片描述
这种作法是为了获取 View 的宽或高做为 LinearGradient 的构造参数。若是渐变效果与 View 的宽或高无关,则无需使用此作法。另外此作法的渐变效果是总体的。若是想要实现 TextView 中每一行文本都渐变的话,能够参考下面的作法二

作法二

直接设置 Shadercode

Shader shader = new LinearGradient(0, 0, 0, textView.getLineHeight(),
	        Color.RED, Color.BLUE, Shader.TileMode.REPEAT);
	textView.getPaint().setShader(shader);
	textView.setText("哈喽,benio\n哈喽,benio\n哈喽,benio");
复制代码

效果以下

在这里插入图片描述
多行渐变,效果不错。可是这种作法有一点缺陷,那就是全部文字都变成渐变色了。假设咱们只须要部分字符是渐变色的话,这种方式就不太合理了。特别是在一些使用了 Span 的场景下。

骚操做

要实现部分文字颜色不同的话,第一时间我想到的是 Span。先看下官方提供的 ForegroundColorSpan

public class ForegroundColorSpan extends CharacterStyle implements UpdateAppearance, ParcelableSpan {

    private final int mColor;

    public ForegroundColorSpan(@ColorInt int color) {
        mColor = color;
    }
	...

    /** * Updates the color of the TextPaint to the foreground color. */
    @Override
    public void updateDrawState(@NonNull TextPaint textPaint) {
    	// 就是这里改了颜色
        textPaint.setColor(mColor);
    }
}
复制代码

能够看到,关键就是 updateDrawState() 方法。咱们能够在该方法内实现想要的样式。接下来咱们参考 ForegroundColorSpan 的作法,依照上面作法二的思路,实现一个渐变色的 Span

class LinearGradientForegroundSpan extends CharacterStyle implements UpdateAppearance {
    private int startColor;
    private int endColor;
    private int lineHeight;

    public LinearGradientForegroundSpan(int startColor, int endColor, int lineHeight) {
        this.startColor = startColor;
        this.endColor = endColor;
        this.lineHeight = lineHeight;
    }

    @Override
    public void updateDrawState(TextPaint tp) {
        tp.setShader(new LinearGradient(0, 0, 0, lineHeight,
                startColor, endColor, Shader.TileMode.REPEAT));
    }
}
复制代码

测试代码

SpannableString part1 = new SpannableString("哈喽,");
	part1.setSpan(new LinearGradientForegroundSpan(Color.RED, Color.LTGRAY, textView.getLineHeight()),
	        0, part1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
	SpannableStringBuilder sb = new SpannableStringBuilder();
	sb.append(part1);
	sb.append("benio\n");
	
	SpannableString part2 = new SpannableString("哈喽,benio\n哈喽,benio");
	part2.setSpan(new LinearGradientForegroundSpan(Color.RED, Color.LTGRAY, textView.getLineHeight()),
	        0, part2.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
	sb.append(part2);
	textView.setText(sb);
复制代码

效果以下

在这里插入图片描述
若是还不能知足你的需求,能够将 Shader 做为参数传入 Span 中

class ShaderForegroundSpan extends CharacterStyle implements UpdateAppearance {
    private Shader mShader;

    public ShaderForegroundSpan(Shader shader) {
        mShader = shader;
    }

    @Override
    public void updateDrawState(TextPaint tp) {
        tp.setShader(mShader);
    }
}
复制代码

小结

文本颜色渐变的原理都是经过建立一个 LinearGradient 对象,而后其设置到 TextView 的画笔中实现的。构造 LinearGradient 的参数不一样,渐变效果也不同

  • 作法一:渐变效果与 View 的宽或高相关。适用于全部文本总体渐变的场景
  • 作法二:渐变效果与行相关,每行的渐变效果一致。适用于每行文本渐变效果一致的场景
  • 作法三:用 Span 来实现,适用于局部文本渐变,多行文本渐变的场景

参考

相关文章
相关标签/搜索