目标
通过 ColorTrackTextView 来展示一种文字进度条效果,其中一部分文本以原始颜色显示,另一部分文本以目标颜色显示,随着进度的变化,逐步改变文字颜色的展示。
最终效果如下:
1. 结构分析
- 文本显示:该控件将展示文本内容,文本的颜色随着进度的变化而变化。
- 进度条效果:文本的颜色变化会基于一个进度值(0f 到 1f),从一个颜色(原始颜色)逐渐过渡到另一个颜色(目标颜色)。
- 支持方向:文本颜色的过渡可以是从左到右,也可以是从右到左。
2. 实现思路
- 初始化画笔:我们需要两个画笔,分别绘制未变化的颜色和变化后的颜色。
- 计算绘制位置:根据进度计算文本的变化区间和显示位置。
- 剪切区域:使用 canvas.clipRect() 来控制不同进度下文本显示的区域。
- 动态更新进度:通过设置进度值并调用 invalidate() 来刷新视图,使文本颜色过渡。
3. 关键技术点解析
我们用到了 Canvas 类的几个重要方法,特别是 clipRect()、save() 和 restore()。这些方法对于自定义绘制文本的效果至关重要。
自定义 TextView:通过继承 AppCompatTextView 来创建自定义控件。利用系统原有的属性,可以省去一些步骤
canvas.clipRect()
功能
canvas.clipRect() 方法用于限制 Canvas 上绘制内容的区域,即设置一个矩形区域作为画布的可绘制区域,只有在这个区域内的绘制操作才会被执行,超出该区域的部分会被裁剪掉。
因为我们要达到的目标是一个文字两种颜色,两种颜色需要分别绘制,因为不可能只绘制部分字体,这里使用 canvas.clipRect() 的目的就是把裁剪区域外的字体扔掉。也可以理解为 clipRect 就是一个剪刀。
方法
public void clipRect(int left, int top, int right, int bottom);
public void clipRect(Rect rect);
public void clipRect(float left, float top, float right, float bottom);
接受一个 Rect 对象 或四个坐标,直接定义裁剪矩形的区域。
canvas.save()
canvas.save() 会将当前的画布状态(包括变换矩阵、剪裁区域、画笔、绘制属性等)保存到栈中。这样,之后对画布的操作就不会影响到原本的画布状态,保证每次的绘制操作都是局部的。相当于记录个快照。
方法
public int save();
public int save(int saveFlags);
保存当前画布的状态。带有标志位参数,可以指定保存哪些部分的状态,例如是否保存剪切区域、变换矩阵等。常用的标志位是 Canvas.ALL_SAVE_FLAG(保存所有状态)。
canvas.restore()
canvas.restore() 方法用于恢复上次保存的画布状态。你可以在绘制过程中做一些修改(如变换矩阵、裁剪区域等),然后恢复到之前的状态,继续进行绘制操作。
方法
public void restore();
通过 save() 方法保存了画布的状态之后,可以在需要时通过 restore() 恢复画布的状态,以便不影响后续绘制。
在 onDraw() 方法中,我们使用 save() 和 restore() 来保护每次对 Canvas 状态的修改不相互干扰。例如,每次使用 clipRect() 时,都先保存当前的画布状态,然后修改裁剪区域,完成绘制后,再调用 restore() 恢复原始状态,确保其他绘制操作不受影响。
save() 和 restore() 两个方法的作用可能在理解起来有点困难,虽然 Canvas 本身是一个单一的对象,但通过 save() 和 restore(),可以在 同一个 Canvas 上创建多个“画布状态”。只可意会不可言传,MD,好玄幻。
这两个方法可以理解成是 “记住”和“恢复” 画布状态的工具。
4. 定义自定义属性
定义两种颜色:文本的原始颜色,和改变的颜色。这些属性可以通过 res/values/attrs.xml
文件来定义:
<declare-styleable name="ColorTrackTextView">
<attr name="originColor" format="color"/>
<attr name="changeColor" format="color"/>
</declare-styleable>
5. 初始化视图元素
初始化画笔和两种颜色。
private void initPaint(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ColorTrackTextView);
// 获取用户设置的颜色,若未设置则使用默认颜色
int initialColor = typedArray.getColor(R.styleable.ColorTrackTextView_originColor, getTextColors().getDefaultColor());
int changedColor = typedArray.getColor(R.styleable.ColorTrackTextView_changeColor, getTextColors().getDefaultColor(