preface

In recent development, the effect of text color gradient was implemented. What, text color gradient, too? I don’t like it, but I can only say ok…

Let’s start with the final image

Normal operation

There are two common ways to do this, and the principle is the same. Both create a LinearGradient object and set it into the TextView’s brush.

So let’s take a look at the LinearGradient

LinearGradient

Shader subclass, used to implement linear gradient effects. Common constructors are as follows

public LinearGradient(float x0, 
                      float y0, 
                      float x1, 
                      float y1, 
                      int color0, 
                      int color1, 
                      Shader.TileMode tile)
Copy the code

Parameters that

  • (x0, y0) : coordinates of the start point of the gradient
  • (x1, y1) : coordinates of the end of the gradient
  • Color0: gradient start color
  • Color1: Gradient terminates color
  • Tile: Fill mode
    • CLAMP: edge stretching. Fill the range outside the region with the edge color
    • -Leonard: I don’t want to REPEAT myself. Repeat the filling in both horizontal and vertical directions
    • MIRROR: MIRROR mode. The filling is repeated in a mirror image in both horizontal and vertical directions, with gaps between adjacent images

Practice a

Inherit TextView, override onLayout method and set Shader

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)); }}}Copy the code

LinearGradient is created with a starting coordinate of (0,0) and a ending coordinate of (getWidth(), getHeight()), so the gradient gradient is from the top left to the bottom right. Results the following

            getPaint().setShader(new LinearGradient(0.0.0, getHeight(),
                    startColor,
                    endColor,
                    Shader.TileMode.CLAMP));
Copy the code

Results the following

Approach 2

Set Shader directly

	Shader shader = new LinearGradient(0.0.0, textView.getLineHeight(),
	        Color.RED, Color.BLUE, Shader.TileMode.REPEAT);
	textView.getPaint().setShader(shader);
	textView.setText("Hello benio\n Hello Benio \n Hello Benio");
Copy the code

Results the following

SAO operation

To make part of the text color different, the first thing I thought of was Span. Take a look at the official 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) {
    	// This is where I changed the colortextPaint.setColor(mColor); }}Copy the code

As you can see, the key is the updateDrawState() method. We can implement the desired style within this method. Next, we refer to the practice of ForegroundColorSpan and follow the idea of practice 2 above to achieve a gradient color 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)); }}Copy the code

The test code

	SpannableString part1 = new SpannableString("Hello,");
	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("Hello, Benio \n Hello, Benio");
	part2.setSpan(new LinearGradientForegroundSpan(Color.RED, Color.LTGRAY, textView.getLineHeight()),
	        0, part2.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
	sb.append(part2);
	textView.setText(sb);
Copy the code

Results the following

class ShaderForegroundSpan extends CharacterStyle implements UpdateAppearance {
    private Shader mShader;

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

    @Override
    public void updateDrawState(TextPaint tp) { tp.setShader(mShader); }}Copy the code

summary

Text color gradient works by creating a LinearGradient object and then setting it into the TextView’s brush. Different parameters of constructing LinearGradient will result in different gradient effects

  • Method 1: The gradient effect is related to the width or height of the View. Applies to all scenes where text has an overall gradient
  • Method 2: The gradient effect is related to the row, each row has the same gradient effect. Suitable for scenes where each line of text has the same gradient effect
  • Practice three: use Span to achieve, suitable for local text gradient, multi-line text gradient scene

reference

  • How to Create a Gradient TextView in Android
  • Text with gradient in Android