您的位置:首页技术文章
文章详情页

android - 自定义View中代码流程问题

浏览:54日期:2024-08-30 09:46:31

问题描述

具体代码在最下方给出

android - 自定义View中代码流程问题android - 自定义View中代码流程问题

点击 CHECK 后 就是图二的效果 但是不太明白他这个绘制过程 所以用Log.e调试 还是没看懂点击包含这个View的activity时 log打印为android - 自定义View中代码流程问题

不明白为什么是两次onDraw的打印

然后点击CHECK Log.e打印为(只发了一部分截图)android - 自定义View中代码流程问题

不明白为什么 又打印了两次onDraw然后进行sendEmptyMessageDelayed的递归操作(不知道有没有说错)在invalidate前后分别设置log然后每次在handleMessage中判断的时候 为什么 又要打印onDraw(还是两次)

E/AAA: onDrawE/AAA: onDrawE/AAA: invalidate 1 + 0E/AAA: invalidate 1 + 1E/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);//从资源文件获取BitmapmHandler = 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==falseanimCurrentPage = 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); }}

问题解答

回答1:

这是系统的机制, 绘制几次你不用去关心.你只应该关心, 什么状态, 应该绘制什么样的图.用试图使用绘制次数来作精确的参考. (当然, 某些动画可以使用这个onDraw的同时改变状态)

回答2:

首先,我对我的答案并不是特别肯定,甚至希望他是错的

产生这种问题的罪魁祸首是下面的两个BUTTON...Button继承于TextView,然后TextView有这样一个特性,当为他设置Text或者他的Text变化的时候,他会调用父ViewGroup的onLayout方法,这样父ViewGroup会再一次layout,再一次drawChild,从而再次执行onDraw,将button换成ImageView之后,就不会出现题问中的情况了。

至于为什么之前onDraw执行了两次而不是三次就不知道了

相关文章: