记录一次Android自定义View的难忘教训

一个倒计时控件:CountView extend JustifyTextView extend ImageView,CountView倒计时触发后,调用JustifyTextView中的方法setText(String text);使用invalidate(),进行重绘,而不是使用TextView setText(),调用requestLayout进行重绘,原因是:requestLayout()方法会一层一层调用父布局的:requestLayout()(会导致父布局重新进行测量、布局和绘制流程,这样会影响某些View不能正常显示:例如滑动显示菜单,布局变动时会自动关闭菜单显示,这不是我想要的结果),而invalidate()只针对当前变动的View进行重绘

主要问题:第一个方法会不断调用,第一次调用后会调用onDraw方法,但是UI上没显示画的结果,并且随后再也不调用onDraw方法

//JustifyTextView.java 一秒调用一次
public void setText(String text) {
        this.text = text;
        invalidate();
    }

//正常情况下每次调用invalidate();会调用下面的方法
@Override
protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (paint == null){
            initPaint();
        }
        Paint.FontMetrics fm = paint.getFontMetrics();
        float baseline = fm.descent - fm.ascent;

        canvas.drawText(text, desiredWidth/2, baseline, paint);
}

分析问题可能产生的原因:

  • onDraw没调用是因为 invalidate(),调用不对?换做下面几个方法都不行,看来不是这个问题
requestLayout();
((View)getParent()).invalidate();
 forceLayout();
  • 尝试在子View(CountView)中进行绘制,仍然只绘制一次
  • 对ImageView设置背景,仍然无果
  • 对View绘制的起始坐标进行多次设置尝试,仍然不行
canvas.drawText(text, x, y, paint);
  • 改变xml布局中控件的wrap_content为指定宽高,终于显示出来
android:layout_width="wrap_content"
android:layout_height="wrap_content"
# 改为
android:layout_width="100dp"
android:layout_height="100dp"

最后

  • 通过重新实现onMeasure方法(xml中仍然采用wrap_content),动态设置View的宽高,达到正常显示的效果
 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width;
        int height;

        //Measure Width
        if (widthMode == MeasureSpec.EXACTLY) {
            //Must be this size
            width = widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            //Can't be bigger than...
            width = Math.min(desiredWidth, widthSize);
        } else {
            //Be whatever you want
            width = desiredWidth;
        }

        //Measure Height
        if (heightMode == MeasureSpec.EXACTLY) {
            //Must be this size
            height = heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            //Can't be bigger than...
            height = Math.min(desiredHeight, heightSize);
        } else {
            //Be whatever you want
            height = desiredHeight;
        }

        //MUST CALL THIS
        setMeasuredDimension(width, height);
    }
感悟:View绘制异常时,后面不会再调用:onDraw;没能静下心来,抓问题的主要矛盾,分析产生问题的主要原因,导致做了许多无用的尝试,浪费了将近一天时间!

你可能感兴趣的:(记录一次Android自定义View的难忘教训)