为什么在调用invalidate()后onDraw方法没有被调用?

54

我在stackoverflow上找到了很多帖子,但我仍然无法解决我的问题。这是我的代码片段:

public class MyView extends RelativeLayout {

Button b1;
Button b2;
Context sContext;
public static int i = 0;
private int w = 400;
private int h = 400;
private int w2 = 100;
private int h2 = 100;

public MyView(Context context) {
    super(context);
    sContext = context;
    init();
}

public MyView(Context context, AttributeSet attrs) {
    super(context, attrs);
    sContext = context;
    init();
}

private void init() {
    b1 = new Button(sContext);
    addView(b1);
    b1.setBackgroundColor(Color.YELLOW);

    b1.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            if (w >= 600) {
                MyView.this.setBackgroundColor(Color.GREEN);
                //b1.setBackgroundColor(Color.RED);
            } else {
                MyView.this.setX(100);
            }

            MyView.this.invalidate();
            w += 100;
            w2 += 20;
        }

    });
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //b1.setBackgroundColor(Color.RED);
    Toast.makeText(sContext, ""+i, Toast.LENGTH_SHORT).show();
    ++i;
}
}

请问为什么我按下 b1 的前三次 onDraw() 没有被调用呢?因为我每次按下 b1 都调用了 invalidate()。非常感谢!


请查看此链接,可能会有所帮助:http://stackoverflow.com/questions/17576970/android-when-ondraw-is-called/17577083#17577083。 - Raghunandan
5个回答

99

默认情况下,所有的ViewGroup子类都不会调用它们的onDraw方法,你需要通过调用setWillNotDraw(false)链接来启用该方法。


24

从链接@ Borrowing from the link @

Android自定义布局 - onDraw()从不被调用

尝试下面的方法,它可以工作

1.如果您正在扩展ViewGroup(在您的情况下为RelativeLayout),则应该覆盖dispatchDraw()而不是onDraw()

有关此主题的讨论@

https://groups.google.com/forum/?fromgroups=#!topic/android-developers/oLccWfszuUo

protected void dispatchDraw (Canvas canvas)

由draw调用以绘制子视图。这可以被派生类重写,在其子视图绘制之前(但在自身视图绘制之后)控制

参数

画布 在其上绘制视图的画布

示例

public class Hello  extends Activity {

    private MyView myView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

                super.onCreate(savedInstanceState);
                Log.e("hello", "hello");
                this.myView = new MyView(this);
                setContentView(this.myView);

    }
     public class MyView extends RelativeLayout
       {

      private Paint myPaint = new Paint();
      private int[] numbers;
      public MyView(Context paramContext)
      {
        super(paramContext);
        Log.e("MyView", "MyView");
        setFocusable(true);
        setBackgroundResource(R.drawable.ic_launcher);
      }
      @Override
      protected void dispatchDraw(Canvas canvas){         

            super.dispatchDraw(canvas);     
            Log.i("...............","drawing");   
        }

  }
}

2. 如果您在构造函数中覆盖了 onDraw,则调用 setWillNotDraw(false) 应该可以解决问题。

http://developer.android.com/reference/android/view/View.html#setWillNotDraw(boolean)

public MyView(Context context) {
super(context);
sContext = context;
init();
setWillNotDraw(false); 
}

即使这不是正确答案,dispatchDraw() 为我解决了问题! :D 谢谢 +1000! - ahmed_khan_89
1
@ahmed_khan_89,你说这不是正确的答案是什么意思?答案是正确的。回答中指出了两种解决方法。 - Raghunandan
抱歉造成误解。我的意思是,那个提问者没有选择这个答案作为正确答案。我并不是说这个答案是错误的。 - ahmed_khan_89
@ahmed_khan_89 噢,好的。 - Raghunandan

14

为了调用onDraw方法,您需要调用setWillNotDraw(false);

private void init() {
  setWillNotDraw(false);
  ...
}

0

我在使用4.1 Jelly Bean API 16时遇到了C#中OnDraw未被调用的问题。我从使用API 16 SDK编译切换到使用7.1 Nougat SDK编译,问题完全解决了。我的清单文件中仍然有最小API 16的设置,并且在我的Jelly Beam avd上运行良好。


0
在我的情况下,onDraw 没有被调用,因为我返回了视图的宽度或高度为 0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接