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

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com