android自定义变色文字

自定义一个可部分变色的TextView,类似歌词效果:

最终效果如上图,可以从左往右变色也可以从右往左变色。
实现的思路是将文字分成两部分来绘制,
在这里插入图片描述
如这个helloworld,定好一个位置将竖线左边的画笔颜色改成红色,后面的画笔颜色为默认颜色分成两部分来绘制。因为最终使用的是canvas.drawText来绘制,但是文字“HelloWorld”是一个整体,必须进行裁剪。具体方法是使用canvas.clipRect,绘制左边文字时裁剪文字开始到红色位置的部份,右边文字裁剪红线位置到文字末端部份。
动态变色效果则是通过改变红线位置,不断重绘即可。
关键代码

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

重写了onDraw方法,根据progress得到分割的位置position,然后调用了两次drawText,分别绘制0~position和position到末端的文字。

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

drawText方法的关键是根据position进行了clipRect裁剪。因为我们对画布进行了操作所以一进来需要保存画布的状态,在绘制完成后使用restore进行恢复,否则右边部分的绘制将会失效(因为画布裁剪只剩下了左边部分)。
最后提供一个改变分割位置的方法:

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

外部使用的时候直接输入百分比就可以,在onDraw中根据比例计算实际分割位置

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

下面是完整代码---------------------------------------------------------------------------------------------------------------------------->>>>>>

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自定义属性

<?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>

简单使用:
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" />
   .................

Activity中使用SeekBar改变进度

         .....................
        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) {
    
    

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

完。

猜你喜欢

转载自blog.csdn.net/weixin_40652755/article/details/127345440