具体代码在最下方给出
点击 CHECK 后 就是图二的效果
但是不太明白他这个绘制过程 所以用Log.e调试 还是没看懂
点击包含这个View的activity时 log打印为
不明白为什么是两次onDraw
的打印
然后点击CHECK Log.e打印为(只发了一部分截图)
不明白为什么 又打印了两次onDraw
然后进行sendEmptyMessageDelayed的递归操作(不知道有没有说错)
在invalidate前后分别设置log
然后每次在handleMessage
中判断的时候 为什么 又要打印onDraw(还是两次)
E/AAA: onDraw
E/AAA: onDraw
E/AAA: invalidate 1 + 0
E/AAA: invalidate 1 + 1
E/AAA: Count=1
public class CheckView extends View {
private static final int ANIM_NULL = 0; //动画状态-没有
private static final int ANIM_CHECK = 1; //动画状态-开启
private static final int ANIM_UNCHECK = 2; //动画状态-结束
private Context mContext; // 上下文
private int mWidth, mHeight; // 宽高
private Handler mHandler; // handler
private Paint mPaint;
private Bitmap okBitmap;
private int animCurrentPage = -1; // 当前页码
private int animMaxPage = 13; // 总页数
private int animDuration = 500; // 动画时长
private int animState = ANIM_NULL; // 动画状态
private boolean isCheck = false; // 是否只选中状态
public CheckView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.e("AAA","构造方法CheckView + 0");
init(context);
Log.e("AAA","构造方法CheckView + 1");
}
/**
* 初始化
* @param context
*/
private void init(Context context) {
mContext = context;
mPaint = new Paint();
mPaint.setColor(0xffFF5317);//设置画笔颜色
mPaint.setStyle(Paint.Style.FILL);//设置画笔风格
mPaint.setAntiAlias(true);//抗锯齿
okBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.checkes);//从资源文件获取Bitmap
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (animCurrentPage < animMaxPage && animCurrentPage >= 0) {// 点击之前-1 <13 && -1>=0 点击后 0 < 13 && 0 >=0
Log.e("AAA","invalidate 1 + 0");
invalidate();//重绘 ==> 调用onDraw方法,重绘View中变化的部分
Log.e("AAA","invalidate 1 + 1");
if (animState == ANIM_NULL)// 动画状态==没有
return;
if (animState == ANIM_CHECK) {//动画状态==开启
animCurrentPage++;//当前页数++
} else if (animState == ANIM_UNCHECK) {//动画状态==关闭
animCurrentPage--;//当前页数--
}
this.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
Log.e("AAA", "Count=" + animCurrentPage);
} else {
if (isCheck) { //isCheck==false
animCurrentPage = animMaxPage - 1;// -1 = 13-1
} else {
animCurrentPage = -1;
}
Log.e("AAA","invalidate 2 + 0");
invalidate();//重绘 ondraw中 使用invalidate 非UI线程中 使用 postInvalidate
Log.e("AAA","invalidate 2 + 1");
animState = ANIM_NULL;// 动画状态==没有
}
}
};
}
/**
* View大小确定
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
Log.e("AAA","onSizeChanged");
}
/**
* 绘制内容
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.e("AAA","onDraw");
// 移动坐标系到画布中央
canvas.translate(mWidth / 2, mHeight / 2);
// 绘制背景圆形
canvas.drawCircle(0, 0, 240, mPaint);
// 得出图像边长
int sideLength = okBitmap.getHeight();
// 得到图像选区 和 实际绘制位置
Rect src = new Rect(sideLength * animCurrentPage, 0, sideLength * (animCurrentPage + 1), sideLength);
Rect dst = new Rect(-200, -200, 200, 200);
// 绘制
canvas.drawBitmap(okBitmap, src, dst, null);
}
/**
* 选择
*/
public void check() {
if (animState != ANIM_NULL || isCheck)
return;
animState = ANIM_CHECK;
animCurrentPage = 0;
Log.e("AAA","check + 1");
mHandler.sendEmptyMessageDelayed(0, animDuration / animMaxPage); // (0,500/13)
isCheck = true;
Log.e("AAA","check + 2");
}
/**
* 取消选择
*/
public void unCheck() {
if (animState != ANIM_NULL || (!isCheck))
return;
animState = ANIM_UNCHECK;
animCurrentPage = animMaxPage - 1;
mHandler.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
isCheck = false;
}
/**
* 设置动画时长
* @param animDuration
*/
public void setAnimDuration(int animDuration) {
if (animDuration <= 0)
return;
this.animDuration = animDuration;
}
/**
* 设置背景圆形颜色
* @param color
*/
public void setBackgroundColor(int color){
mPaint.setColor(color);
}
}
이것이 시스템의 메커니즘입니다.
몇 번을 그리든 상관하지 마세요.
어떤 상태, 어떤 그림을 그려야 하는지만 신경 쓰면 됩니다. 정확한 드로잉을 위해 드로우 횟수를 활용해 보세요. (물론 일부 애니메이션에서는 이를 onDraw에서 동시에 사용하여 상태를 변경할 수도 있습니다.)
우선 내 대답이 잘 모르겠습니다. 그가 틀렸기를 바랍니다
이 문제의 원인은 다음 두 BUTTON입니다. Button은 TextView에서 상속되며 TextView에는 이러한 기능이 있습니다. Text가 설정되거나 Text가 변경되면 상위 ViewGroup 메서드가 호출됩니다. , 상위 ViewGroup이 다시 레이아웃되고 drawChild가 다시 실행되고 버튼을 ImageView로 바꾼 후에는 문제의 상황이 발생하지 않습니다.
왜 onDraw가 세 번이 아닌 두 번 실행되었는지 모르겠습니다