View.onDraw() --- 什么时候被调用?

38

我在扩展的View的onDraw()方法中放置了一个Log.d()调用,以便查看它被调用的频率和时间。它在视图实例化时被调用,这并不奇怪。但是我注意到,它在每次由onTouchEvent()处理的触摸操作中都会被调用,尽管我的代码与图形完全无关。然而,在Views的文档中,我似乎找不到有关onDraw()何时被调用的任何信息。我并不真正关心我的特定项目(这对我没有问题),我只想知道是否有某个列表或类似的东西显示View的操作顺序,特别是是什么导致onDraw()被调用。


“它在视图实例化时被调用” - View 可以通过从 XML 布局中进行膨胀或直接从代码中构建来创建。当 onFinishInflate 完成时,尚未知道任何测量值,只有当 View 实际“渲染”时才会计算它们(即当 onAttachedToWindowonMeasureonLayoutonDraw 被调用时)。 - samus
6个回答

66

据我所知,当以下情况之一发生时,View的onDraw()方法会被调用:

  1. 视图被初始绘制
  2. 每当视图上调用invalidate()方法时

无论何时需要,您或系统都可以调用invalidate()方法。例如,许多视图在触摸操作时改变外观,如EditText获取轮廓和光标,按钮处于按下状态等。由于这个原因,视图在触摸上重新绘制。

我同意有一个详细介绍视图工作方式的文档将是很好的,如果有人知道其中之一的存在并且知道如何找到它,请告诉我们。


这并不适用于 ViewGroup。请参见我的答案 https://dev59.com/RGct5IYBdhLWcg3wqfP9#34367199 - Chad Bingham
需要注意的一点是,View的onDraw()方法不能保证在invalidate()之后立即被调用。正如文档所述,如果视图可见,则onDraw(android.graphics.Canvas)方法将在未来的某个时间点被调用。 - Sơn Phan
@Raghav:我尝试了你建议的方法(在View中而不是ViewGroup中)。在我的示例中,invalidate()调用并没有触发onDraw()方法。(请参见https://stackoverflow.com/questions/70038233/how-to-update-a-view-element-with-a-canvas-in-android) - VanessaF

23

onDraw()方法在调用invalidate()时被调用。

但你需要知道对于ViewGroups,onDraw()不会像你期望的那样被调用。相反,onDispatchDraw()方法会被调用。

然而,在ViewGroup中,你可以在构造函数中调用setWillNotDraw(false)使得onDraw()方法在调用invalidate()时被调用。

请参考这个答案


9
如果您为视图设置了背景可绘制对象,则在调用其onDraw()方法之前,该视图将为您进行绘制。
当视图附加到窗口时,onAttachedToWindow()方法会被调用。此时,它具有一个表面并将开始绘制。请注意,此函数保证在onDraw(android.graphics.Canvas)之前调用,但它可以在第一个onDraw之前的任何时间调用-包括在onMeasure(int,int)之前或之后。
invalidate()方法将由dirty定义的区域标记为需要绘制。如果视图可见,则在将来的某个时间调用onDraw(android.graphics.Canvas)方法。

有没有一种方法可以在调用onDraw()之前拦截,您想看一下我的问题吗?http://stackoverflow.com/questions/19052952/bitmap-change-will-make-view-auto-refresh-before-ondraw-and-regardless-invalid - VinceStyling

1

记住一件重要的事情,尽量减少不带参数调用invalidate()函数。相反,尽量最大化使用带有四个参数的invalidate()函数。因为绘制整个视图非常昂贵。第二种方法只会刷新视图的一部分。


1
这个答案已经过时了,API已经更新,它会自己计算“脏矩形”,因此这个函数已经被弃用。 - Aleksandar Stefanović

1

什么时候会调用onDraw方法(请查看this以获取更多详细信息)

当Android认为您的视图应该重新绘制时,将调用onDraw方法。这可能是在动画过程中,每帧都会调用onDraw方法。当布局发生更改并且您的视图在屏幕上重新定位时,也会调用它。

但是,如果您的视图内部的某些数据已更改,并且您想确保视图被重新绘制,则不能直接调用onDraw方法。相反,您应该调用invalidate方法,告诉视图它需要重新绘制自己。


0
除了上述内容之外:软键盘在调整窗口大小以合理适应“键盘”后会导致 View.invalidate()-->View.onDraw() 序列。自定义的 View.onDraw() 必须保持自身处于一种可以预见这种可能性的状态。
这种现象解释了为什么你在带有蓝牙键盘的平板电脑上开发和测试的应用程序一旦进入真实世界就会变得不堪一击 (-:).

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