【问题标题】:What triggers a View's measure() to be called什么触发了 View 的 measure() 被调用
【发布时间】:2011-10-20 06:17:26
【问题描述】:

在我的应用程序中,我的 View 的 onMeasure() 覆盖之一有一个无限循环。从我的 onMeasure 中的断点开始调试源代码,我能够一直跟踪自己一直到堆栈跟踪到 PhoneWindow$DecorView 的 measure()(我的视图层次结构中最顶层的类),它由 ViewRoot 调用.performTraversals()。现在从这里开始,如果我继续前行,我最终会通过 Looper.loop() 类中的消息再次调用 PhoneWindow$DecorView 的 measure()。我猜有些东西排队了一条需要重新测量的消息,比如无效。

我的问题是,需要在视图上进行度量调用的触发因素是什么?

根据我对布局/测量/绘制过程的理解,这只会在特定视图上调用 invalidate() 方法时发生,并且会向下渗透并为该视图执行布局/测量/绘制通道无效及其所有的孩子。我会假设我的视图层次结构中最顶层的视图正在失效。

但是,我已经明确地在我拥有的每个 invalidate 调用上设置了一个断点,并且没有以某种无限的方式调用 invalidate。所以我认为情况并非如此。是否有另一种方法来触发测量通过?内部可能会触发这种情况吗?看到没有什么是无限无效的,我有点想不通。

【问题讨论】:

  • 什么意思?如果您在滚动视图中滚动 .. 它会失效.. 您不必致电 invalidate()
  • 在我的代码中,当我对视图执行无效调用时,有很多明确的点。我要问的是在幕后什么会使措施无效并强制采取措施,以及除无效以外的其他任何措施都会强制采取措施。很高兴知道在 scrollView 中滚动之类的操作会导致无效。

标签: android layout measure


【解决方案1】:

为了触发自定义视图的测量传递,您必须调用 requestLayout() 方法。 例如,如果您正在实现一个扩展 View 的自定义视图,并且它的行为类似于 TextView,您可以编写这样的 setText 方法:

/**
 * Sets the string value of the view.
 * @param text the string to write
 */
public void setText(String text) {
    this.text = text;

            //calculates the new text width
    textWidth = mTextPaint.measureText(text);

    //force re-calculating the layout dimension and the redraw of the view
    requestLayout();
    invalidate();
}

【讨论】:

  • 你真的需要requestLayout()invalidate()吗?我的印象是invalidate() 会两者兼得。
  • Invalidate 只会导致再次绘制视图。 requestLayout 将导致它被布局和绘制。
  • 您只需要调用invalidate() 重新创建与视图关联的Display List 对象即可重绘它。它将在您的根视图上调用 invalidateChildInParent 方法,该方法将代表您安排测量和布局步骤。测量和布局步骤都将自上而下遍历您的视图层次结构,每个子 ViewGroup 将负责调用每个子级的测量和布局方法。无论如何,这可能有点技术性,但这就是引擎盖下的内容。另外,这就是为什么文档建议您保持层次结构扁平化 - 以减少额外成本。
  • 这没有回答问题。问题是什么触发而不是如何触发。
  • @metter 表示上面调用 invalidate() 是多余的?
【解决方案2】:

好吧,如果您要更改视图的内容,它最终将不得不调用 invalidate()。例如,您有一个 TextView,其中包含名为“Text 1”的文本。现在,您将同一 TextView 的文本更改为“Text 2”。这里也会调用 invalidate。

所以基本上,当视图发生变化时,通常情况下,您会期望调用 invalidate 方法,并相应地调用 measure()。

例如,查看 TextView 的源代码。 http://www.google.com/codesearch#uX1GffpyOZk/core/java/android/widget/TextView.java&q=TextView%20package:android&type=cs

计算无效调用的次数。有不少。

【讨论】:

  • 感谢库马尔的回复。我没有看到我的代码不断更改 View 值。但是,您的回复确实给了我一个很好的调试途径。我在 View.class 的 inavlidate() 方法上设置了一个断点,不幸的是,当我处于这个无限循环中时,我没有休息。检查 invalidate 是如何工作的,看起来它在 ViewRoot 上调用了 invalidateChild 并将 Rect 标记为脏,但我认为我无法访问 ViewRoot 内部的 break :(
  • 好吧,如果不深入了解您在应用程序中究竟做了什么,很难指出。可能是,父项中的某些内容发生了变化,这也尝试重新绘制子项。
  • 我可以看到在自定义视图中invalidate() 不会导致measure() 调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-03
  • 2010-12-02
  • 2017-04-09
  • 1970-01-01
相关资源
最近更新 更多