public class CountView extends View implements View.OnClickListener {
private Paint mPaint;
private Rect mBounds;
private int mCounter;
public CountView(Context context, AttributeSet attrs) {
super(context,attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBounds = new Rect();
setOnClickListener(this);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.BLUE);
canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
mPaint.setColor(Color.YELLOW);
mPaint.setTextSize(30);
String text = String.valueOf(mCounter);
mPaint.getTextBounds(text, 0, text.length(), mBounds);
float textWidth = mBounds.width();
float textHeight = mBounds.height();
canvas.drawText(text, getWidth() / 2 - textWidth / 2, getHeight() / 2
+ textHeight / 2, mPaint);
}
@Override
public void onClick(View view) {
mCounter++;
invalidate();
}
}
一、视图状态
视图状态的种类非常多,一共有十几种类型,不过多数情况下我们只会使用到其中的几种,因此这里我们也就只去分析最常用的几种视图状态。
1. enabled
表示当前视图是否可用。可以调用setEnable()方法来改变视图的可用状态,传入true表示可用,传入false表示不可用。它们之间最大的区别在于,不可用的视图是无法响应onTouch事件的。
2. focused
表示当前视图是否获得到焦点。通常情况下有两种方法可以让视图获得焦点,即通过键盘的上下左右键切换视图,以及调用requestFocus()方法。而现在的Android手机几乎都没有键盘了,
因此基本上只可以使用requestFocus()这个办法来让视图获得焦点了。
而requestFocus()方法也不能保证一定可以让视图获得焦点,它会有一个布尔值的返回值,
如果返回true说明获得焦点成功,返回false说明获得焦点失败。一般只有视图在focusable和focusable in touch mode同时成立的情况下才能成功获取焦点,比如说EditText。
3. window_focused
表示当前视图是否处于正在交互的窗口中,这个值由系统自动决定,应用程序不能进行改变。
4. selected
表示当前视图是否处于选中状态。一个界面当中可以有多个视图处于选中状态,调用setSelected()方法能够改变视图的选中状态,传入true表示选中,传入false表示未选中。
5. pressed
表示当前视图是否处于按下状态。可以调用setPressed()方法来对这一状态进行改变,传入true表示按下,传入false表示未按下。通常情况下这个状态都是由系统自动赋值的,
但开发者也可以自己调用这个方法来进行改变。
二、视图重绘
虽然视图会在Activity加载完成之后自动绘制到屏幕上,但是我们完全有理由在与Activity进行交互的时候要求动态更新视图,比如改变视图的状态、以及显示或隐藏某个控件等。那在这个时候,
之前绘制出的视图其实就已经过期了,此时我们就应该对视图进行重绘。
调用视图的setVisibility()、setEnabled()、setSelected()等方法时都会导致视图重绘,而如果我们想要手动地强制让视图进行重绘,可以调用invalidate()方法来实现。
当然了,setVisibility()、setEnabled()、setSelected()等方法的内部其实也是通过调用invalidate()方法来实现的,那么就让我们来看一看invalidate()方法的代码是什么样的吧。
View的源码中会有数个invalidate()方法的重载和一个invalidateDrawable()方法,当然它们的原理都是相同的,因此我们只分析其中一种,代码如下所示:
基础图形绘制
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
//stroke表示描边 fill表示填充不包括描边
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10);
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
canvas.drawPoint(100,100,paint);
float[] points = new float[]{100,200,200,300,400,500};
canvas.drawPoints(points,paint);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
//stroke表示描边 fill表示填充不包括描边
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10);
paint.setAntiAlias(true);
//画一条线
canvas.drawLine(100,200,100,400,paint);
//绘制一堆线
float[] points = new float[]{100,200,200,300,300,400,500,600};
canvas.drawLines(points,paint);
}
//计算文本的长度
Rect rect = new Rect();
paint.getTextBounds("123",0,"123".length(),rect);
rect.width();
rect.height();
//重新绘制
invalidate();//只能在主线程调用
postInvalidate();//可以在主线程和子线程调用
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
canvas.drawCircle(width/2,height/2,height/2-2,paint);
// 设置文字大小要在测量之前
paint.setTextSize(30);
//测量文字的大小
Rect rect = new Rect();
paint.getTextBounds(text,0,text.length(),rect);
textWidth = rect.width();
textHeight = rect.height();
canvas.drawText(text,width/2-(textWidth/2),height/2+(textHeight/2),paint);
}
private Paint mPaint;
private Rect mBounds;
private int mCounter;
public CountView(Context context, AttributeSet attrs) {
super(context,attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBounds = new Rect();
setOnClickListener(this);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.BLUE);
canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
mPaint.setColor(Color.YELLOW);
mPaint.setTextSize(30);
String text = String.valueOf(mCounter);
mPaint.getTextBounds(text, 0, text.length(), mBounds);
float textWidth = mBounds.width();
float textHeight = mBounds.height();
canvas.drawText(text, getWidth() / 2 - textWidth / 2, getHeight() / 2
+ textHeight / 2, mPaint);
}
@Override
public void onClick(View view) {
mCounter++;
invalidate();
}
}
一、视图状态
视图状态的种类非常多,一共有十几种类型,不过多数情况下我们只会使用到其中的几种,因此这里我们也就只去分析最常用的几种视图状态。
1. enabled
表示当前视图是否可用。可以调用setEnable()方法来改变视图的可用状态,传入true表示可用,传入false表示不可用。它们之间最大的区别在于,不可用的视图是无法响应onTouch事件的。
2. focused
表示当前视图是否获得到焦点。通常情况下有两种方法可以让视图获得焦点,即通过键盘的上下左右键切换视图,以及调用requestFocus()方法。而现在的Android手机几乎都没有键盘了,
因此基本上只可以使用requestFocus()这个办法来让视图获得焦点了。
而requestFocus()方法也不能保证一定可以让视图获得焦点,它会有一个布尔值的返回值,
如果返回true说明获得焦点成功,返回false说明获得焦点失败。一般只有视图在focusable和focusable in touch mode同时成立的情况下才能成功获取焦点,比如说EditText。
3. window_focused
表示当前视图是否处于正在交互的窗口中,这个值由系统自动决定,应用程序不能进行改变。
4. selected
表示当前视图是否处于选中状态。一个界面当中可以有多个视图处于选中状态,调用setSelected()方法能够改变视图的选中状态,传入true表示选中,传入false表示未选中。
5. pressed
表示当前视图是否处于按下状态。可以调用setPressed()方法来对这一状态进行改变,传入true表示按下,传入false表示未按下。通常情况下这个状态都是由系统自动赋值的,
但开发者也可以自己调用这个方法来进行改变。
二、视图重绘
虽然视图会在Activity加载完成之后自动绘制到屏幕上,但是我们完全有理由在与Activity进行交互的时候要求动态更新视图,比如改变视图的状态、以及显示或隐藏某个控件等。那在这个时候,
之前绘制出的视图其实就已经过期了,此时我们就应该对视图进行重绘。
调用视图的setVisibility()、setEnabled()、setSelected()等方法时都会导致视图重绘,而如果我们想要手动地强制让视图进行重绘,可以调用invalidate()方法来实现。
当然了,setVisibility()、setEnabled()、setSelected()等方法的内部其实也是通过调用invalidate()方法来实现的,那么就让我们来看一看invalidate()方法的代码是什么样的吧。
View的源码中会有数个invalidate()方法的重载和一个invalidateDrawable()方法,当然它们的原理都是相同的,因此我们只分析其中一种,代码如下所示:
基础图形绘制
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
//stroke表示描边 fill表示填充不包括描边
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10);
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
canvas.drawPoint(100,100,paint);
float[] points = new float[]{100,200,200,300,400,500};
canvas.drawPoints(points,paint);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
//stroke表示描边 fill表示填充不包括描边
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10);
paint.setAntiAlias(true);
//画一条线
canvas.drawLine(100,200,100,400,paint);
//绘制一堆线
float[] points = new float[]{100,200,200,300,300,400,500,600};
canvas.drawLines(points,paint);
}
//计算文本的长度
Rect rect = new Rect();
paint.getTextBounds("123",0,"123".length(),rect);
rect.width();
rect.height();
//重新绘制
invalidate();//只能在主线程调用
postInvalidate();//可以在主线程和子线程调用
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
canvas.drawCircle(width/2,height/2,height/2-2,paint);
// 设置文字大小要在测量之前
paint.setTextSize(30);
//测量文字的大小
Rect rect = new Rect();
paint.getTextBounds(text,0,text.length(),rect);
textWidth = rect.width();
textHeight = rect.height();
canvas.drawText(text,width/2-(textWidth/2),height/2+(textHeight/2),paint);
}