From 020e0ef55ce73d94284db593f895bfc3a0b520e9 Mon Sep 17 00:00:00 2001 From: xster Date: Thu, 14 Jun 2018 13:17:08 -0700 Subject: [PATCH] Add some more dart doc to RepaintBoundary (#17183) --- .../lib/src/foundation/diagnostics.dart | 2 +- packages/flutter/lib/src/rendering/debug.dart | 9 +++- .../flutter/lib/src/rendering/object.dart | 6 +++ packages/flutter/lib/src/widgets/basic.dart | 52 +++++++++++++++++-- .../flutter/lib/src/widgets/media_query.dart | 6 +-- 5 files changed, 64 insertions(+), 11 deletions(-) diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart index d929c799e88..44208dc751e 100644 --- a/packages/flutter/lib/src/foundation/diagnostics.dart +++ b/packages/flutter/lib/src/foundation/diagnostics.dart @@ -743,7 +743,7 @@ abstract class DiagnosticsNode { String get _separator => showSeparator ? ':' : ''; - /// Serialize the node excluding its descendents to a JSON map. + /// Serialize the node excluding its descendants to a JSON map. /// /// Subclasses should override if they have additional properties that are /// useful for the GUI tools that consume this JSON. diff --git a/packages/flutter/lib/src/rendering/debug.dart b/packages/flutter/lib/src/rendering/debug.dart index 104bfd7fa19..99f8e16e3b9 100644 --- a/packages/flutter/lib/src/rendering/debug.dart +++ b/packages/flutter/lib/src/rendering/debug.dart @@ -38,6 +38,11 @@ bool debugPaintLayerBordersEnabled = false; bool debugPaintPointersEnabled = false; /// Overlay a rotating set of colors when repainting layers in checked mode. +/// +/// See also: +/// +/// * [RepaintBoundary], which can be used to contain repaints when unchanged +/// areas are being excessively repainted. bool debugRepaintRainbowEnabled = false; /// Overlay a rotating set of colors when repainting text in checked mode. @@ -103,12 +108,12 @@ bool debugCheckIntrinsicSizes = false; /// /// * [debugPrintLayouts], which does something similar for layout but using /// console output. -/// /// * [debugProfileBuildsEnabled], which does something similar for widgets /// being rebuilt, and [debugPrintRebuildDirtyWidgets], its console /// equivalent. -/// /// * The discussion at [RendererBinding.drawFrame]. +/// * [RepaintBoundary], which can be used to contain repaints when unchanged +/// areas are being excessively repainted. bool debugProfilePaintsEnabled = false; /// Setting to true will cause all clipping effects from the layer tree to be diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 85b3d9cecfd..5aa707ec221 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -1871,6 +1871,12 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im /// Once [markNeedsPaint] has been called on a render object, /// [debugNeedsPaint] returns true for that render object until just after /// the pipeline owner has called [paint] on the render object. + /// + /// See also: + /// + /// * [RepaintBoundary], to scope a subtree of render objects to their own + /// layer, thus limiting the number of nodes that [markNeedsPaint] must mark + /// dirty. void markNeedsPaint() { assert(owner == null || !owner.debugDoingPaint); if (_needsPaint) diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index be5c27eeb04..a5752e9d80f 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -4774,11 +4774,53 @@ class Listener extends SingleChildRenderObjectWidget { /// /// This widget creates a separate display list for its child, which /// can improve performance if the subtree repaints at different times than -/// the surrounding parts of the tree. Specifically, when the child does not -/// repaint but its parent does, we can re-use the display list we recorded -/// previously. Similarly, when the child repaints but the surround tree does -/// not, we can re-record its display list without re-recording the display list -/// for the surround tree. +/// the surrounding parts of the tree. +/// +/// This is useful since [RenderObject.paint] may be triggered even if its +/// associated [Widget] instances did not change or rebuild. A [RenderObject] +/// will repaint whenever any [RenderObject] that shares the same [Layer] is +/// marked as being dirty and needing paint (see [RenderObject.markNeedsPaint]), +/// such as when an ancestor scrolls or when an ancestor or descendant animates. +/// +/// Containing [RenderObject.paint] to parts of the render subtree that are +/// actually visually changing using [RepaintBoundary] explicitly or implicitly +/// is therefore critical to minimizing redundant work and improving the app's +/// performance. +/// +/// When a [RenderObject] is flagged as needing to paint via +/// [RenderObject.markNeedsPaint], the nearest ancestor [RenderObject] with +/// [RenderObject.isRepaintBoundary], up to possibly the root of the application, +/// is requested to repaint. That nearest ancestor's [RenderObject.paint] method +/// will cause _all_ of its descendant [RenderObject]s to repaint in the same +/// layer. +/// +/// [RepaintBoundary] is therefore used, both while propagating the +/// `markNeedsPaint` flag up the render tree and while traversing down the +/// render tree via [RenderObject.paintChild], to strategically contain repaints +/// to the render subtree that visually changed for performance. This is done +/// because the [RepaintBoundary] widget creates a [RenderObject] that always +/// has a [Layer], decoupling ancestor render objects from the descendant +/// render objects. +/// +/// [RepaintBoundary] has the further side-effect of possibly hinting to the +/// engine that it should further optimize animation performance if the render +/// subtree behind the [RepaintBoundary] is sufficiently complex and is static +/// while the surrounding tree changes frequently. In those cases, the engine +/// may choose to pay a one time cost of rasterizing and caching the pixel +/// values of the subtree for faster future GPU re-rendering speed. +/// +/// Several framework widgets insert [RepaintBoundary] widgets to mark natural +/// separation points in applications. For instance, contents in Material Design +/// drawers typically don't change while the drawer opens and closes, so +/// repaints are automatically contained to regions inside or outside the drawer +/// when using the [Drawer] widget during transitions. +/// +/// See also: +/// +/// * [debugRepaintRainbowEnabled], a debugging flag to help visually monitor +/// render tree repaints in a running app. +/// * [debugProfilePaintsEnabled], a debugging flag to show render tree +/// repaints in the observatory's timeline view. class RepaintBoundary extends SingleChildRenderObjectWidget { /// Creates a widget that isolates repaints. const RepaintBoundary({ Key key, Widget child }) : super(key: key, child: child); diff --git a/packages/flutter/lib/src/widgets/media_query.dart b/packages/flutter/lib/src/widgets/media_query.dart index d5cd755ad3e..a9440e0167e 100644 --- a/packages/flutter/lib/src/widgets/media_query.dart +++ b/packages/flutter/lib/src/widgets/media_query.dart @@ -98,7 +98,7 @@ class MediaQueryData { /// If you consumed this padding (e.g. by building a widget that envelops or /// accounts for this padding in its layout in such a way that children are /// no longer exposed to this padding), you should remove this padding - /// for subsequent descendents in the widget tree by inserting a new + /// for subsequent descendants in the widget tree by inserting a new /// [MediaQuery] widget using the [MediaQuery.removePadding] factory. /// /// See also: @@ -283,7 +283,7 @@ class MediaQuery extends InheritedWidget { /// /// This should be inserted into the widget tree when the [MediaQuery] padding /// is consumed by a widget in such a way that the padding is no longer - /// exposed to the widget's descendents or siblings. + /// exposed to the widget's descendants or siblings. /// /// The [context] argument is required, must not be null, and must have a /// [MediaQuery] in scope. @@ -327,7 +327,7 @@ class MediaQuery extends InheritedWidget { /// /// This should be inserted into the widget tree when the [MediaQuery] view /// insets are consumed by a widget in such a way that the view insets are no - /// longer exposed to the widget's descendents or siblings. + /// longer exposed to the widget's descendants or siblings. /// /// The [context] argument is required, must not be null, and must have a /// [MediaQuery] in scope.