1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'animated_cross_fade.dart';
6/// @docImport 'animated_switcher.dart';
7/// @docImport 'implicit_animations.dart';
8/// @docImport 'navigator.dart';
9/// @docImport 'transitions.dart';
10library;
11
12import 'package:flutter/rendering.dart';
13
14import 'basic.dart';
15import 'framework.dart';
16import 'sliver.dart';
17import 'ticker_provider.dart';
18
19/// Whether to show or hide a child.
20///
21/// By default, the [visible] property controls whether the [child] is included
22/// in the subtree or not; when it is not [visible], the [replacement] child
23/// (typically a zero-sized box) is included instead.
24///
25/// A variety of flags can be used to tweak exactly how the child is hidden.
26/// (Changing the flags dynamically is discouraged, as it can cause the [child]
27/// subtree to be rebuilt, with any state in the subtree being discarded.
28/// Typically, only the [visible] flag is changed dynamically.)
29///
30/// These widgets provide some of the facets of this one:
31///
32/// * [Opacity], which can stop its child from being painted.
33/// * [Offstage], which can stop its child from being laid out or painted.
34/// * [TickerMode], which can stop its child from being animated.
35/// * [ExcludeSemantics], which can hide the child from accessibility tools.
36/// * [IgnorePointer], which can disable touch interactions with the child.
37///
38/// Using this widget is not necessary to hide children. The simplest way to
39/// hide a child is just to not include it, or, if a child _must_ be given (e.g.
40/// because the parent is a [StatelessWidget]) then to use [SizedBox.shrink]
41/// instead of the child that would otherwise be included.
42///
43/// See also:
44///
45/// * [AnimatedSwitcher], which can fade from one child to the next as the
46/// subtree changes.
47/// * [AnimatedCrossFade], which can fade between two specific children.
48/// * [SliverVisibility], the sliver equivalent of this widget.
49class Visibility extends StatelessWidget {
50 /// Control whether the given [child] is [visible].
51 ///
52 /// The [maintainSemantics] and [maintainInteractivity] arguments can only be
53 /// set if [maintainSize] is set.
54 ///
55 /// The [maintainSize] argument can only be set if [maintainAnimation] is set.
56 ///
57 /// The [maintainAnimation] argument can only be set if [maintainState] is
58 /// set.
59 const Visibility({
60 super.key,
61 required this.child,
62 this.replacement = const SizedBox.shrink(),
63 this.visible = true,
64 this.maintainState = false,
65 this.maintainAnimation = false,
66 this.maintainSize = false,
67 this.maintainSemantics = false,
68 this.maintainInteractivity = false,
69 }) : assert(
70 maintainState || !maintainAnimation,
71 'Cannot maintain animations if the state is not also maintained.',
72 ),
73 assert(
74 maintainAnimation || !maintainSize,
75 'Cannot maintain size if animations are not maintained.',
76 ),
77 assert(
78 maintainSize || !maintainSemantics,
79 'Cannot maintain semantics if size is not maintained.',
80 ),
81 assert(
82 maintainSize || !maintainInteractivity,
83 'Cannot maintain interactivity if size is not maintained.',
84 );
85
86 /// Control whether the given [child] is [visible].
87 ///
88 /// This is equivalent to the default [Visibility] constructor with all
89 /// "maintain" fields set to true. This constructor should be used in place of
90 /// an [Opacity] widget that only takes on values of `0.0` or `1.0`, as it
91 /// avoids extra compositing when fully opaque.
92 const Visibility.maintain({
93 super.key,
94 required this.child,
95 this.visible = true,
96 }) : maintainState = true,
97 maintainAnimation = true,
98 maintainSize = true,
99 maintainSemantics = true,
100 maintainInteractivity = true,
101 replacement = const SizedBox.shrink(); // Unused since maintainState is always true.
102
103 /// The widget to show or hide, as controlled by [visible].
104 ///
105 /// {@macro flutter.widgets.ProxyWidget.child}
106 final Widget child;
107
108 /// The widget to use when the child is not [visible], assuming that none of
109 /// the `maintain` flags (in particular, [maintainState]) are set.
110 ///
111 /// The normal behavior is to replace the widget with a zero by zero box
112 /// ([SizedBox.shrink]).
113 ///
114 /// See also:
115 ///
116 /// * [AnimatedCrossFade], which can animate between two children.
117 final Widget replacement;
118
119 /// Switches between showing the [child] or hiding it.
120 ///
121 /// The `maintain` flags should be set to the same values regardless of the
122 /// state of the [visible] property, otherwise they will not operate correctly
123 /// (specifically, the state will be lost regardless of the state of
124 /// [maintainState] whenever any of the `maintain` flags are changed, since
125 /// doing so will result in a subtree shape change).
126 ///
127 /// Unless [maintainState] is set, the [child] subtree will be disposed
128 /// (removed from the tree) while hidden.
129 final bool visible;
130
131 /// Whether to maintain the [State] objects of the [child] subtree when it is
132 /// not [visible].
133 ///
134 /// Keeping the state of the subtree is potentially expensive (because it
135 /// means all the objects are still in memory; their resources are not
136 /// released). It should only be maintained if it cannot be recreated on
137 /// demand. One example of when the state would be maintained is if the child
138 /// subtree contains a [Navigator], since that widget maintains elaborate
139 /// state that cannot be recreated on the fly.
140 ///
141 /// If this property is true, an [Offstage] widget is used to hide the child
142 /// instead of replacing it with [replacement].
143 ///
144 /// If this property is false, then [maintainAnimation] must also be false.
145 ///
146 /// Dynamically changing this value may cause the current state of the
147 /// subtree to be lost (and a new instance of the subtree, with new [State]
148 /// objects, to be immediately created if [visible] is true).
149 final bool maintainState;
150
151 /// Whether to maintain animations within the [child] subtree when it is
152 /// not [visible].
153 ///
154 /// To set this, [maintainState] must also be set.
155 ///
156 /// Keeping animations active when the widget is not visible is even more
157 /// expensive than only maintaining the state.
158 ///
159 /// One example when this might be useful is if the subtree is animating its
160 /// layout in time with an [AnimationController], and the result of that
161 /// layout is being used to influence some other logic. If this flag is false,
162 /// then any [AnimationController]s hosted inside the [child] subtree will be
163 /// muted while the [visible] flag is false.
164 ///
165 /// If this property is true, no [TickerMode] widget is used.
166 ///
167 /// If this property is false, then [maintainSize] must also be false.
168 ///
169 /// Dynamically changing this value may cause the current state of the
170 /// subtree to be lost (and a new instance of the subtree, with new [State]
171 /// objects, to be immediately created if [visible] is true).
172 final bool maintainAnimation;
173
174 /// Whether to maintain space for where the widget would have been.
175 ///
176 /// To set this, [maintainAnimation] and [maintainState] must also be set.
177 ///
178 /// Maintaining the size when the widget is not [visible] is not notably more
179 /// expensive than just keeping animations running without maintaining the
180 /// size, and may in some circumstances be slightly cheaper if the subtree is
181 /// simple and the [visible] property is frequently toggled, since it avoids
182 /// triggering a layout change when the [visible] property is toggled. If the
183 /// [child] subtree is not trivial then it is significantly cheaper to not
184 /// even keep the state (see [maintainState]).
185 ///
186 /// If this property is false, [Offstage] is used.
187 ///
188 /// If this property is false, then [maintainSemantics] and
189 /// [maintainInteractivity] must also be false.
190 ///
191 /// Dynamically changing this value may cause the current state of the
192 /// subtree to be lost (and a new instance of the subtree, with new [State]
193 /// objects, to be immediately created if [visible] is true).
194 ///
195 /// See also:
196 ///
197 /// * [AnimatedOpacity] and [FadeTransition], which apply animations to the
198 /// opacity for a more subtle effect.
199 final bool maintainSize;
200
201 /// Whether to maintain the semantics for the widget when it is hidden (e.g.
202 /// for accessibility).
203 ///
204 /// To set this, [maintainSize] must also be set.
205 ///
206 /// By default, with [maintainSemantics] set to false, the [child] is not
207 /// visible to accessibility tools when it is hidden from the user. If this
208 /// flag is set to true, then accessibility tools will report the widget as if
209 /// it was present.
210 final bool maintainSemantics;
211
212 /// Whether to allow the widget to be interactive when hidden.
213 ///
214 /// To set this, [maintainSize] must also be set.
215 ///
216 /// By default, with [maintainInteractivity] set to false, touch events cannot
217 /// reach the [child] when it is hidden from the user. If this flag is set to
218 /// true, then touch events will nonetheless be passed through.
219 final bool maintainInteractivity;
220
221 /// Tells the visibility state of an element in the tree based off its
222 /// ancestor [Visibility] elements.
223 ///
224 /// If there's one or more [Visibility] widgets in the ancestor tree, this
225 /// will return true if and only if all of those widgets have [visible] set
226 /// to true. If there is no [Visibility] widget in the ancestor tree of the
227 /// specified build context, this will return true.
228 ///
229 /// This will register a dependency from the specified context on any
230 /// [Visibility] elements in the ancestor tree, such that if any of their
231 /// visibilities changes, the specified context will be rebuilt.
232 static bool of(BuildContext context) {
233 bool isVisible = true;
234 BuildContext ancestorContext = context;
235 InheritedElement? ancestor = ancestorContext.getElementForInheritedWidgetOfExactType<_VisibilityScope>();
236 while (isVisible && ancestor != null) {
237 final _VisibilityScope scope = context.dependOnInheritedElement(ancestor) as _VisibilityScope;
238 isVisible = scope.isVisible;
239 ancestor.visitAncestorElements((Element parent) {
240 ancestorContext = parent;
241 return false;
242 });
243 ancestor = ancestorContext.getElementForInheritedWidgetOfExactType<_VisibilityScope>();
244 }
245 return isVisible;
246 }
247
248 @override
249 Widget build(BuildContext context) {
250 Widget result = child;
251 if (maintainSize) {
252 result = _Visibility(
253 visible: visible,
254 maintainSemantics: maintainSemantics,
255 child: IgnorePointer(
256 ignoring: !visible && !maintainInteractivity,
257 child: result,
258 ),
259 );
260 } else {
261 assert(!maintainInteractivity);
262 assert(!maintainSemantics);
263 assert(!maintainSize);
264 if (maintainState) {
265 if (!maintainAnimation) {
266 result = TickerMode(enabled: visible, child: result);
267 }
268 result = Offstage(
269 offstage: !visible,
270 child: result,
271 );
272 } else {
273 assert(!maintainAnimation);
274 assert(!maintainState);
275 result = visible ? child : replacement;
276 }
277 }
278 return _VisibilityScope(isVisible: visible, child: result);
279 }
280
281 @override
282 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
283 super.debugFillProperties(properties);
284 properties.add(FlagProperty('visible', value: visible, ifFalse: 'hidden', ifTrue: 'visible'));
285 properties.add(FlagProperty('maintainState', value: maintainState, ifFalse: 'maintainState'));
286 properties.add(FlagProperty('maintainAnimation', value: maintainAnimation, ifFalse: 'maintainAnimation'));
287 properties.add(FlagProperty('maintainSize', value: maintainSize, ifFalse: 'maintainSize'));
288 properties.add(FlagProperty('maintainSemantics', value: maintainSemantics, ifFalse: 'maintainSemantics'));
289 properties.add(FlagProperty('maintainInteractivity', value: maintainInteractivity, ifFalse: 'maintainInteractivity'));
290 }
291}
292
293/// Inherited widget that allows descendants to find their visibility status.
294class _VisibilityScope extends InheritedWidget {
295 const _VisibilityScope({required this.isVisible, required super.child});
296
297 final bool isVisible;
298
299 @override
300 bool updateShouldNotify(_VisibilityScope old) {
301 return isVisible != old.isVisible;
302 }
303}
304
305/// Whether to show or hide a sliver child.
306///
307/// By default, the [visible] property controls whether the [sliver] is included
308/// in the subtree or not; when it is not [visible], the [replacementSliver] is
309/// included instead.
310///
311/// A variety of flags can be used to tweak exactly how the sliver is hidden.
312/// (Changing the flags dynamically is discouraged, as it can cause the [sliver]
313/// subtree to be rebuilt, with any state in the subtree being discarded.
314/// Typically, only the [visible] flag is changed dynamically.)
315///
316/// These widgets provide some of the facets of this one:
317///
318/// * [SliverOpacity], which can stop its sliver child from being painted.
319/// * [SliverOffstage], which can stop its sliver child from being laid out or
320/// painted.
321/// * [TickerMode], which can stop its child from being animated.
322/// * [ExcludeSemantics], which can hide the child from accessibility tools.
323/// * [SliverIgnorePointer], which can disable touch interactions with the
324/// sliver child.
325///
326/// Using this widget is not necessary to hide children. The simplest way to
327/// hide a child is just to not include it. If a child _must_ be given (e.g.
328/// because the parent is a [StatelessWidget]), then including a childless
329/// [SliverToBoxAdapter] instead of the child that would otherwise be included
330/// is typically more efficient than using [SliverVisibility].
331///
332/// See also:
333///
334/// * [Visibility], the equivalent widget for boxes.
335class SliverVisibility extends StatelessWidget {
336 /// Control whether the given [sliver] is [visible].
337 ///
338 /// The [maintainSemantics] and [maintainInteractivity] arguments can only be
339 /// set if [maintainSize] is set.
340 ///
341 /// The [maintainSize] argument can only be set if [maintainAnimation] is set.
342 ///
343 /// The [maintainAnimation] argument can only be set if [maintainState] is
344 /// set.
345 const SliverVisibility({
346 super.key,
347 required this.sliver,
348 this.replacementSliver = const SliverToBoxAdapter(),
349 this.visible = true,
350 this.maintainState = false,
351 this.maintainAnimation = false,
352 this.maintainSize = false,
353 this.maintainSemantics = false,
354 this.maintainInteractivity = false,
355 }) : assert(
356 maintainState || !maintainAnimation,
357 'Cannot maintain animations if the state is not also maintained.',
358 ),
359 assert(
360 maintainAnimation || !maintainSize,
361 'Cannot maintain size if animations are not maintained.',
362 ),
363 assert(
364 maintainSize || !maintainSemantics,
365 'Cannot maintain semantics if size is not maintained.',
366 ),
367 assert(
368 maintainSize || !maintainInteractivity,
369 'Cannot maintain interactivity if size is not maintained.',
370 );
371
372 /// Control whether the given [sliver] is [visible].
373 ///
374 /// This is equivalent to the default [SliverVisibility] constructor with all
375 /// "maintain" fields set to true. This constructor should be used in place of
376 /// a [SliverOpacity] widget that only takes on values of `0.0` or `1.0`, as it
377 /// avoids extra compositing when fully opaque.
378 const SliverVisibility.maintain({
379 super.key,
380 required this.sliver,
381 this.replacementSliver = const SliverToBoxAdapter(),
382 this.visible = true,
383 }) : maintainState = true,
384 maintainAnimation = true,
385 maintainSize = true,
386 maintainSemantics = true,
387 maintainInteractivity = true;
388
389 /// The sliver to show or hide, as controlled by [visible].
390 final Widget sliver;
391
392 /// The widget to use when the sliver child is not [visible], assuming that
393 /// none of the `maintain` flags (in particular, [maintainState]) are set.
394 ///
395 /// The normal behavior is to replace the widget with a childless
396 /// [SliverToBoxAdapter], which by default has a geometry of
397 /// [SliverGeometry.zero].
398 final Widget replacementSliver;
399
400 /// Switches between showing the [sliver] or hiding it.
401 ///
402 /// The `maintain` flags should be set to the same values regardless of the
403 /// state of the [visible] property, otherwise they will not operate correctly
404 /// (specifically, the state will be lost regardless of the state of
405 /// [maintainState] whenever any of the `maintain` flags are changed, since
406 /// doing so will result in a subtree shape change).
407 ///
408 /// Unless [maintainState] is set, the [sliver] subtree will be disposed
409 /// (removed from the tree) while hidden.
410 final bool visible;
411
412 /// Whether to maintain the [State] objects of the [sliver] subtree when it is
413 /// not [visible].
414 ///
415 /// Keeping the state of the subtree is potentially expensive (because it
416 /// means all the objects are still in memory; their resources are not
417 /// released). It should only be maintained if it cannot be recreated on
418 /// demand. One example of when the state would be maintained is if the sliver
419 /// subtree contains a [Navigator], since that widget maintains elaborate
420 /// state that cannot be recreated on the fly.
421 ///
422 /// If this property is true, a [SliverOffstage] widget is used to hide the
423 /// sliver instead of replacing it with [replacementSliver].
424 ///
425 /// If this property is false, then [maintainAnimation] must also be false.
426 ///
427 /// Dynamically changing this value may cause the current state of the
428 /// subtree to be lost (and a new instance of the subtree, with new [State]
429 /// objects, to be immediately created if [visible] is true).
430 final bool maintainState;
431
432 /// Whether to maintain animations within the [sliver] subtree when it is
433 /// not [visible].
434 ///
435 /// To set this, [maintainState] must also be set.
436 ///
437 /// Keeping animations active when the widget is not visible is even more
438 /// expensive than only maintaining the state.
439 ///
440 /// One example when this might be useful is if the subtree is animating its
441 /// layout in time with an [AnimationController], and the result of that
442 /// layout is being used to influence some other logic. If this flag is false,
443 /// then any [AnimationController]s hosted inside the [sliver] subtree will be
444 /// muted while the [visible] flag is false.
445 ///
446 /// If this property is true, no [TickerMode] widget is used.
447 ///
448 /// If this property is false, then [maintainSize] must also be false.
449 ///
450 /// Dynamically changing this value may cause the current state of the
451 /// subtree to be lost (and a new instance of the subtree, with new [State]
452 /// objects, to be immediately created if [visible] is true).
453 final bool maintainAnimation;
454
455 /// Whether to maintain space for where the sliver would have been.
456 ///
457 /// To set this, [maintainAnimation] must also be set.
458 ///
459 /// Maintaining the size when the sliver is not [visible] is not notably more
460 /// expensive than just keeping animations running without maintaining the
461 /// size, and may in some circumstances be slightly cheaper if the subtree is
462 /// simple and the [visible] property is frequently toggled, since it avoids
463 /// triggering a layout change when the [visible] property is toggled. If the
464 /// [sliver] subtree is not trivial then it is significantly cheaper to not
465 /// even keep the state (see [maintainState]).
466 ///
467 /// If this property is false, [SliverOffstage] is used.
468 ///
469 /// If this property is false, then [maintainSemantics] and
470 /// [maintainInteractivity] must also be false.
471 ///
472 /// Dynamically changing this value may cause the current state of the
473 /// subtree to be lost (and a new instance of the subtree, with new [State]
474 /// objects, to be immediately created if [visible] is true).
475 final bool maintainSize;
476
477 /// Whether to maintain the semantics for the sliver when it is hidden (e.g.
478 /// for accessibility).
479 ///
480 /// To set this, [maintainSize] must also be set.
481 ///
482 /// By default, with [maintainSemantics] set to false, the [sliver] is not
483 /// visible to accessibility tools when it is hidden from the user. If this
484 /// flag is set to true, then accessibility tools will report the widget as if
485 /// it was present.
486 final bool maintainSemantics;
487
488 /// Whether to allow the sliver to be interactive when hidden.
489 ///
490 /// To set this, [maintainSize] must also be set.
491 ///
492 /// By default, with [maintainInteractivity] set to false, touch events cannot
493 /// reach the [sliver] when it is hidden from the user. If this flag is set to
494 /// true, then touch events will nonetheless be passed through.
495 final bool maintainInteractivity;
496
497 @override
498 Widget build(BuildContext context) {
499 if (maintainSize) {
500 Widget result = sliver;
501 result = SliverIgnorePointer(
502 ignoring: !visible && !maintainInteractivity,
503 sliver: result,
504 );
505 return _SliverVisibility(
506 visible: visible,
507 maintainSemantics: maintainSemantics,
508 sliver: result,
509 );
510 }
511 assert(!maintainInteractivity);
512 assert(!maintainSemantics);
513 assert(!maintainSize);
514 if (maintainState) {
515 Widget result = sliver;
516 if (!maintainAnimation) {
517 result = TickerMode(enabled: visible, child: sliver);
518 }
519 return SliverOffstage(
520 sliver: result,
521 offstage: !visible,
522 );
523 }
524 assert(!maintainAnimation);
525 assert(!maintainState);
526 return visible ? sliver : replacementSliver;
527 }
528
529 @override
530 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
531 super.debugFillProperties(properties);
532 properties.add(FlagProperty('visible', value: visible, ifFalse: 'hidden', ifTrue: 'visible'));
533 properties.add(FlagProperty('maintainState', value: maintainState, ifFalse: 'maintainState'));
534 properties.add(FlagProperty('maintainAnimation', value: maintainAnimation, ifFalse: 'maintainAnimation'));
535 properties.add(FlagProperty('maintainSize', value: maintainSize, ifFalse: 'maintainSize'));
536 properties.add(FlagProperty('maintainSemantics', value: maintainSemantics, ifFalse: 'maintainSemantics'));
537 properties.add(FlagProperty('maintainInteractivity', value: maintainInteractivity, ifFalse: 'maintainInteractivity'));
538 }
539}
540
541// A widget that conditionally hides its child, but without the forced compositing of `Opacity`.
542//
543// A fully opaque `Opacity` widget is required to leave its opacity layer in the layer tree. This
544// forces all parent render objects to also composite, which can break a simple scene into many
545// different layers. This can be significantly more expensive, so the issue is avoided by a
546// specialized render object that does not ever force compositing.
547class _Visibility extends SingleChildRenderObjectWidget {
548 const _Visibility({ required this.visible, required this.maintainSemantics, super.child });
549
550 final bool visible;
551 final bool maintainSemantics;
552
553 @override
554 _RenderVisibility createRenderObject(BuildContext context) {
555 return _RenderVisibility(visible, maintainSemantics);
556 }
557
558 @override
559 void updateRenderObject(BuildContext context, _RenderVisibility renderObject) {
560 renderObject
561 ..visible = visible
562 ..maintainSemantics = maintainSemantics;
563 }
564}
565
566class _RenderVisibility extends RenderProxyBox {
567 _RenderVisibility(this._visible, this._maintainSemantics);
568
569 bool get visible => _visible;
570 bool _visible;
571 set visible(bool value) {
572 if (value == visible) {
573 return;
574 }
575 _visible = value;
576 markNeedsPaint();
577 }
578
579 bool get maintainSemantics => _maintainSemantics;
580 bool _maintainSemantics;
581 set maintainSemantics(bool value) {
582 if (value == maintainSemantics) {
583 return;
584 }
585 _maintainSemantics = value;
586 markNeedsSemanticsUpdate();
587 }
588
589 @override
590 void visitChildrenForSemantics(RenderObjectVisitor visitor) {
591 if (maintainSemantics || visible) {
592 super.visitChildrenForSemantics(visitor);
593 }
594 }
595
596 @override
597 void paint(PaintingContext context, Offset offset) {
598 if (!visible) {
599 return;
600 }
601 super.paint(context, offset);
602 }
603}
604
605// A widget that conditionally hides its child, but without the forced compositing of `SliverOpacity`.
606//
607// A fully opaque `SliverOpacity` widget is required to leave its opacity layer in the layer tree.
608// This forces all parent render objects to also composite, which can break a simple scene into many
609// different layers. This can be significantly more expensive, so the issue is avoided by a
610// specialized render object that does not ever force compositing.
611class _SliverVisibility extends SingleChildRenderObjectWidget {
612 const _SliverVisibility({ required this.visible, required this.maintainSemantics, Widget? sliver })
613 : super(child: sliver);
614
615 final bool visible;
616 final bool maintainSemantics;
617
618 @override
619 RenderObject createRenderObject(BuildContext context) {
620 return _RenderSliverVisibility(visible, maintainSemantics);
621 }
622
623 @override
624 void updateRenderObject(BuildContext context, _RenderSliverVisibility renderObject) {
625 renderObject
626 ..visible = visible
627 ..maintainSemantics = maintainSemantics;
628 }
629}
630
631class _RenderSliverVisibility extends RenderProxySliver {
632 _RenderSliverVisibility(this._visible, this._maintainSemantics);
633
634 bool get visible => _visible;
635 bool _visible;
636 set visible(bool value) {
637 if (value == visible) {
638 return;
639 }
640 _visible = value;
641 markNeedsPaint();
642 }
643
644 bool get maintainSemantics => _maintainSemantics;
645 bool _maintainSemantics;
646 set maintainSemantics(bool value) {
647 if (value == maintainSemantics) {
648 return;
649 }
650 _maintainSemantics = value;
651 markNeedsSemanticsUpdate();
652 }
653
654 @override
655 void visitChildrenForSemantics(RenderObjectVisitor visitor) {
656 if (maintainSemantics || visible) {
657 super.visitChildrenForSemantics(visitor);
658 }
659 }
660
661 @override
662 void paint(PaintingContext context, Offset offset) {
663 if (!visible) {
664 return;
665 }
666 super.paint(context, offset);
667 }
668}
669