【问题标题】:Why is requestLayout being called directly after invalidate为什么在失效后直接调用requestLayout
【发布时间】:2016-05-18 16:33:35
【问题描述】:

我正在学习自定义视图并想了解 invalidate()requestLayout()

请参考这个答案及其图表:

https://stackoverflow.com/a/25846243/4243687

invalidate() 告诉 Android 视图的状态已经改变,需要重新绘制。

requestLayout() 表示视图的大小可能已经改变,需要重新测量,然后重新绘制。

invalidate() 将调用 dispatchDraw()draw()onDraw(),因此它会重新渲染视图。

另一方面,requestLayout() 几乎可以完成从测量到重新渲染的所有工作。

为什么有这么多示例(甚至是TextView 源代码)调用invalidate(),然后在下一行调用requestLayout()

【问题讨论】:

    标签: android android-view android-view-invalidate


    【解决方案1】:

    invalidate() 专门用于重绘视图的内容。重绘不会同步发生。相反,它会将您的视图区域标记为无效,以便在下一个渲染周期中重新绘制。

    requestLayout() 应该在其中的某些东西可能改变了它的尺寸时使用。在这种情况下,父视图和视图层次结构中的所有其他父视图将需要通过布局传递重新调整自己。

    如果您没有对视图做任何会改变其大小的操作,那么您不必调用requestLayout()

    如果您返回查看TextView 的代码中调用requestLayout() 的位置,则会发现视图边界会受到影响的方法。例如setPadding()setTypeface()setCompoundDrawables()

    所以,当requestLayout()被调用时,应该搭配调用invalidate来确保整个视图被重绘。

    【讨论】:

    • 感谢您的精彩解释,因此将 invalidate() 和 requestLayout() 一起调用以重新绘制我们的视图,并让父视图组(将我们的视图作为子视图)调整自己很好当我们重新绘制时考虑到我们视图可能的大小变化
    • 我有点不清楚为什么你会打电话给invalidate(),同时也打电话给requestLayout()。似乎requestLayout() 总是会导致你的整个视图被重绘;除此之外调用invalidate() 似乎是多余的。
    • @ErsenOsman “我必须调用 invalidate() 来渲染新文本以使其显示出来” 我的意思是这个陈述并不完全正确;调用requestLayout()(没有invalidate())也将呈现新文本。所以,我的问题是,在requestLayout()需要被调用的情况下,你为什么调用invalidate()
    • @ErsenOsman 我也有与 pathfinderelite 相同的问题。我认为这里的混淆是 requestLayout() 会在 onMeasure() 和 onLayout() 之后提示调用 onDraw()。如果确实如此,那么为什么我们需要在 requestLayout() 之后调用 invalidate()。
    • @ErsenOsman requestLayout() 不会触发 onDraw()。所以你是对的。链接:grokbase.com/p/gg/android-developers/12amz5pqv8/…
    【解决方案2】:

    看到the following diagram后,我的印象是调用requestLayout()最终会导致onDraw

    因此,没有必要将它们一起调用,因为这将是多余的。

    invalidate();
    requestLayout();
    

    但是,事实证明,该图表具有误导性。当布局发生变化时,某些视图实际上可能会使自己失效,但这并不确定。 不保证调用requestLayout() 会导致调用onDraw

    我的source(感谢this comment)是Romain Guy(他是Google 的Android 工程师):

    requestLayout() 本身不会导致draw pass,但会导致一些视图 可能会通过调用 invalidate 来响应布局更改。

    因此,为了确定重新布局会导致重绘,您应该将invalidate()requestLayout() 配对。 (但反之则不然。如果您只需要重绘,则无需调用requestLayout()。单个invalidate() 即可。)

    【讨论】:

    • 文章写于2012年,声明调用requestLayout()不保证会调用onDraw在2018年有效吗?
    • @JohnnyFive,我没有看到源代码或文档的更新,否则会建议。所以,是的,它仍然有效。
    【解决方案3】:

    来自Expert Android 的书的相关摘录,回答了这个问题:

    由于 onClick 事件导致尺寸发生变化,我们的 视图需要变得更大并占用更多空间。我们如何表达 那需要Android,好吧,我们请求Layout()。这个方法上 链,标记需要重新测量的每个视图父级。 当最终的父级得到这个请求(视图根)时,父级 安排布局遍历。布局遍历可能会也可能不会导致 在 onDraw 中,尽管在这种情况下它应该。作为一个好的编程 实践中,我们也调用 invalidate() 来确保绘制阶段为 好吧。

    【讨论】:

      【解决方案4】:

      Android docs: Creating a View class

      public boolean isShowText() {
         return mShowText;
      }
      
      public void setShowText(boolean showText) {
         mShowText = showText;
         invalidate();
         requestLayout();
      }
      

      注意 setShowText 调用 invalidate() 和 requestLayout()。这些 调用对于确保视图行为可靠至关重要。你有 在对其属性进行任何更改后使视图无效,这可能 改变它的外观,让系统知道它需要 重绘。同样,如果一个属性,您需要请求一个新的布局 可能影响视图大小或形状的更改。遗忘 这些方法调用可能会导致难以发现的错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-04
        • 1970-01-01
        相关资源
        最近更新 更多