我们先来分析一下如何实现这个效果,原生的TextView使用onDraw()方法绘制要显示的文字。当继承了系统的TextView之后,如果不重写其onDraw()方法,则不会修改TextView的任何效果。可以认为在自定义的TextView中调用TextView类的onDraw()方法来绘制显示的文字,代码如下所示。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
程序调用super.onDraw(canvas)方法来实现原生控件的功能,但是在动用super.onDraw()方法之前和之后,我们都可以实现自己的逻辑,分别在系统绘制文字前后,完成自己的操作,即如下所示。
@Override
protected void onDraw(Canvas canvas) {
//在调父类方法前,实现自己的逻辑,对TextView来说即是在绘制文本内容前
super.onDraw(canvas);
//在调父类方法后,实现自己的逻辑,对TextView来说即是在绘制文本内容后
}
以上就是通过改变控件的绘制行为创建自定义View的思路。有了上面的分析,我们就可以很轻松地实现上图所示的自定义TextView了。我们在构造方法中完成必要对象的初始化工作,如初始化画笔等,代码如下所示。
mPaint1 = new Paint();
mPaint1.setColor(Color.BLUE);
mPaint1.setStyle(Paint.Style.FILL);
mPaint2 = new Paint();
mPaint2.setColor(Color.YELLOW);
mPaint2.setStyle(Paint.Style.FILL);
而代码中最重要的部分则是在onDraw()方法中,为了改变原生的绘制行为,在系统调用super.onDraw(canvas)方法前,也就是在绘制文字之前,绘制两个不同大小的矩形,形成一个重叠效果,再让系统调用super.onDraw(canvas)方法,执行绘制文字的工作。这样,我们就通过改变控件绘制行为,创建了一个新的控件,代码如下所示。
//绘制外层矩形
canvas.drawRect(
0,
0,
getMeasuredWidth(),
getMeasuredHeight(),
mPaint1);
//绘制内层矩形
canvas.drawRect(
10,
10,
getMeasuredWidth() - 10,
getMeasuredHeight() - 10,
mPaint2);
canvas.save();
//绘制文字前平移10像素
canvas.translate(10,0);
//父类完成的方法,即绘制文本
super.onDraw(canvas);
canvas.restore();
此View全文(一些细节解析包含在注释中了):
package com.imooc.systemwidget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
//思路:1.准备画笔,2.绘制。完
public class MyTextView extends TextView {
private Paint mPaint1, mPaint2;//声明画笔对象
public MyTextView(Context context) {
super(context);
initView();
}//三个重载构造函数
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MyTextView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() { //准备画笔
mPaint1 = new Paint();//准备画笔1
mPaint1.setColor(getResources().getColor(
android.R.color.holo_blue_light));
mPaint1.setStyle(Paint.Style.FILL);
mPaint2 = new Paint();//准备画笔2
mPaint2.setColor(Color.YELLOW);
mPaint2.setStyle(Paint.Style.FILL);
}
@Override
protected void onDraw(Canvas canvas) {
// 绘制外层矩形 drawRect乃绘制矩形的方法
// 参数:public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)
// 按ctrl点击方法,自己看
canvas.drawRect(
0,
0,
getMeasuredWidth(),
getMeasuredHeight(),
mPaint1);
// 绘制内层矩形
canvas.drawRect(
10,
10,
getMeasuredWidth() - 10,
getMeasuredHeight() - 10,
mPaint2);
canvas.save();
// 绘制文字前平移10像素
// public void translate(float dx, float dy)
//translate用于平移坐标系
canvas.translate(10, 0);
// 父类完成的方法,即绘制文本
super.onDraw(canvas);
canvas.restore();
Log.d("MyTextView", "MyTextView_onDraw: ");
}
}
下面再来看一个稍微复杂一点的TextView。在前面一个实例中,我们直接使用了Canvas对象来进行图像的绘制,然后利用Android的绘图机制,可以绘制出更复杂丰富的图像。比如可以利用LinearGradient Shader 和Matrix来实现一个动态的文字闪动效果,程序运行效果如下图所示。