android custom color text

Customize a TextView that can partially change color, similar to the effect of lyrics:

the final effect is as shown in the above picture, which can change color from left to right or from right to left.
The idea of ​​implementation is to divide the text into two parts to draw,
insert image description here
such as this helloworld, set a position and change the color of the brush on the left side of the vertical line to red, and the color of the brush behind is the default color to draw in two parts. Because canvas.drawText is finally used to draw, but the text "HelloWorld" is a whole and must be clipped. The specific method is to use canvas.clipRect to cut the part from the beginning of the text to the red position when drawing the left text, and clip the red line position to the end of the text on the right.
The dynamic color changing effect is achieved by changing the position of the red line and redrawing continuously.
key code

 @Override
    protected void onDraw(Canvas canvas) {
    
    
        int position = (int) (getWidth() * progress);
        if (currentOrientation == LEFT_TO_RIGHT) {
    
    
            drawText(canvas, changedPaint, 0, position);//绘制改变颜色的部份
            drawText(canvas, defaultPaint, position, getWidth()); //绘制默认颜色的部份
        } else {
    
    
            drawText(canvas, changedPaint, getWidth() - position, getWidth());
            drawText(canvas, defaultPaint, 0, getWidth() - position);
        }
    }

The onDraw method is rewritten, the position of the segmentation is obtained according to the progress, and then drawText is called twice to draw the text from 0~position and position to the end respectively.

 private void drawText(Canvas canvas, Paint paint, int left, int right) {
    
    
        canvas.save();
        clipRect.set(left, 0, right, getBottom());
        canvas.clipRect(clipRect); //裁剪一部份绘制不同颜色
        // 给boundsRect赋值
        paint.getTextBounds(getText().toString(), 0, getText().toString().length(), boundsRect);
        int dx = (getWidth() - boundsRect.width()) / 2;  //让文字居中
        Paint.FontMetricsInt fontMetricsInt = paint.getFontMetricsInt();
        //fontMetricsInt.bottom为基线到底部的距离为正值,fontMetricsInt.top为基线到顶部的距离,为负值
        int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;//文字y中心到基线的距离
        int baseLine = getHeight() / 2 + dy; //基线的位置
        //drawText的第三个参数传的是baseLine的位置
        canvas.drawText(getText().toString(), dx, baseLine, paint);
        canvas.restore();
    }

The key to the drawText method is clipRect clipping according to the position. Because we have operated on the canvas, we need to save the state of the canvas when we come in, and use restore to restore it after the drawing is completed, otherwise the drawing on the right part will be invalid (because only the left part is left after the canvas is clipped).
Finally, a method to change the split position is provided:

  public void setProgress(float progress) {
    
    //改变进度
        this.progress = progress;
        invalidate();
    }

When using it externally, you can directly enter the percentage, and calculate the actual split position according to the ratio in onDraw

  int position = (int) (getWidth() * progress);

Below is the complete code ---------------------------------------------- -------------------------------------------------- ------------------------------->>>>>>

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.TextView;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
//自定义可改变颜色的textView,跟歌词效果类似
public class ChangeColorTextView extends AppCompatTextView {
    
    
    private Paint defaultPaint;
    private Paint changedPaint;
    private float progress = 0f;
    private int currentOrientation = LEFT_TO_RIGHT;
    public static final int LEFT_TO_RIGHT = 0;
    public static final int RIGHT_TO_LEFT = 1;

    //限制输入参数
    @IntDef(value = {
    
    LEFT_TO_RIGHT, RIGHT_TO_LEFT})
    public @interface Orientation{
    
    

    }
    public ChangeColorTextView(Context context) {
    
    
        this(context, null);

    }


    public ChangeColorTextView(Context context, @Nullable AttributeSet attrs) {
    
    
        this(context, attrs, 0);
    }

    public ChangeColorTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    
    
        super(context, attrs, defStyleAttr);
        initPaint(context, attrs);
    }

    //设置从左到右还是右到左
    public void setCurrentOrientation(@Orientation int currentOrientation) {
    
    
        this.currentOrientation = currentOrientation;
    }

    //初始化画笔
    private void initPaint(Context context, AttributeSet attrs) {
    
    
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ChangeColorTextView);
        //读取自定义属性
        int defaultColor = typedArray.getColor(R.styleable.ChangeColorTextView_defaultColor, getTextColors().getDefaultColor());
        int changeColor = typedArray.getColor(R.styleable.ChangeColorTextView_changeColor, getTextColors().getDefaultColor());
        typedArray.recycle();
        defaultPaint = getPaintByColor(defaultColor);
        changedPaint = getPaintByColor(changeColor);
    }

    private Paint getPaintByColor(int Color) {
    
    
        Paint paint = new Paint();
        paint.setAntiAlias(true); //抗锯齿
        paint.setDither(true);//防抖
        paint.setColor(Color);
        paint.setTextSize(getTextSize());
        return paint;
    }

    @Override
    protected void onDraw(Canvas canvas) {
    
    
        int position = (int) (getWidth() * progress);
        if (currentOrientation == LEFT_TO_RIGHT) {
    
    
            drawText(canvas, changedPaint, 0, position);//绘制改变颜色的部份
            drawText(canvas, defaultPaint, position, getWidth()); //绘制默认颜色的部份
        } else {
    
    
            drawText(canvas, changedPaint, getWidth() - position, getWidth());
            drawText(canvas, defaultPaint, 0, getWidth() - position);
        }
    }

    Rect clipRect = new Rect();
    Rect boundsRect = new Rect();

    private void drawText(Canvas canvas, Paint paint, int left, int right) {
    
    
        canvas.save();
        clipRect.set(left, 0, right, getBottom());
        canvas.clipRect(clipRect); //裁剪一部份绘制不同颜色
        // 给boundsRect赋值
        paint.getTextBounds(getText().toString(), 0, getText().toString().length(), boundsRect);
        int dx = (getWidth() - boundsRect.width()) / 2;  //让文字居中
        Paint.FontMetricsInt fontMetricsInt = paint.getFontMetricsInt();
        //fontMetricsInt.bottom为基线到底部的距离为正值,fontMetricsInt.top为基线到顶部的距离,为负值
        int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;//文字y中心到基线的距离
        int baseLine = getHeight() / 2 + dy; //基线的位置
        //drawText的第三个参数传的是baseLine的位置
        canvas.drawText(getText().toString(), dx, baseLine, paint);
        canvas.restore();
    }

    public void setProgress(float progress) {
    
    //改变进度
        this.progress = progress;
        invalidate();
    }
}

attrs.xml custom attributes

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ChangeColorTextView">
        <attr name="defaultColor" format="color"/>
        <attr name="changeColor" format="color"/>
    </declare-styleable>
</resources>

Simple use:
activity.xml

   .................
  <com.sample.changecolortext.ChangeColorTextView
        android:id="@+id/changeColorTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="This is L2R ChangeColorTextView"
        android:textSize="20sp"
        app:changeColor="#ff0000"
        app:defaultColor="#ccc" />
   <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginTop="150dp" />
   .................

Use SeekBar in Activity to change progress

         .....................
        changeColorTextView=findViewById(R.id.changeColorTextView2);
        //改变方向
        //changeColorTextView.setCurrentOrientation(ChangeColorTextView.RIGHT_TO_LEFT);
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    
    
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    
    
                changeColorTextView.setProgress(progress/100f);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
    
    

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
    
    

            }
        });
        .....................

over.

Guess you like

Origin blog.csdn.net/weixin_40652755/article/details/127345440