mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Make InkDecoraiton not paint if the ink is not visible (#122585)
Make InkDecoration not paint if the ink is not visible
This commit is contained in:
parent
4b2853dd44
commit
25174d621e
@ -279,6 +279,7 @@ class _InkState extends State<Ink> {
|
|||||||
if (_ink == null) {
|
if (_ink == null) {
|
||||||
_ink = InkDecoration(
|
_ink = InkDecoration(
|
||||||
decoration: widget.decoration,
|
decoration: widget.decoration,
|
||||||
|
isVisible: Visibility.of(context),
|
||||||
configuration: createLocalImageConfiguration(context),
|
configuration: createLocalImageConfiguration(context),
|
||||||
controller: Material.of(context),
|
controller: Material.of(context),
|
||||||
referenceBox: _boxKey.currentContext!.findRenderObject()! as RenderBox,
|
referenceBox: _boxKey.currentContext!.findRenderObject()! as RenderBox,
|
||||||
@ -286,6 +287,7 @@ class _InkState extends State<Ink> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_ink!.decoration = widget.decoration;
|
_ink!.decoration = widget.decoration;
|
||||||
|
_ink!.isVisible = Visibility.of(context);
|
||||||
_ink!.configuration = createLocalImageConfiguration(context);
|
_ink!.configuration = createLocalImageConfiguration(context);
|
||||||
}
|
}
|
||||||
return widget.child ?? ConstrainedBox(constraints: const BoxConstraints.expand());
|
return widget.child ?? ConstrainedBox(constraints: const BoxConstraints.expand());
|
||||||
@ -329,12 +331,14 @@ class InkDecoration extends InkFeature {
|
|||||||
/// Draws a decoration on a [Material].
|
/// Draws a decoration on a [Material].
|
||||||
InkDecoration({
|
InkDecoration({
|
||||||
required Decoration? decoration,
|
required Decoration? decoration,
|
||||||
|
bool isVisible = true,
|
||||||
required ImageConfiguration configuration,
|
required ImageConfiguration configuration,
|
||||||
required super.controller,
|
required super.controller,
|
||||||
required super.referenceBox,
|
required super.referenceBox,
|
||||||
super.onRemoved,
|
super.onRemoved,
|
||||||
}) : _configuration = configuration {
|
}) : _configuration = configuration {
|
||||||
this.decoration = decoration;
|
this.decoration = decoration;
|
||||||
|
this.isVisible = isVisible;
|
||||||
controller.addInkFeature(this);
|
controller.addInkFeature(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,6 +360,19 @@ class InkDecoration extends InkFeature {
|
|||||||
controller.markNeedsPaint();
|
controller.markNeedsPaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the decoration should be painted.
|
||||||
|
///
|
||||||
|
/// Defaults to true.
|
||||||
|
bool get isVisible => _isVisible;
|
||||||
|
bool _isVisible = true;
|
||||||
|
set isVisible(bool value) {
|
||||||
|
if (value == _isVisible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_isVisible = value;
|
||||||
|
controller.markNeedsPaint();
|
||||||
|
}
|
||||||
|
|
||||||
/// The configuration to pass to the [BoxPainter] obtained from the
|
/// The configuration to pass to the [BoxPainter] obtained from the
|
||||||
/// [decoration], when painting.
|
/// [decoration], when painting.
|
||||||
///
|
///
|
||||||
@ -383,7 +400,7 @@ class InkDecoration extends InkFeature {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void paintFeature(Canvas canvas, Matrix4 transform) {
|
void paintFeature(Canvas canvas, Matrix4 transform) {
|
||||||
if (_painter == null) {
|
if (_painter == null || !isVisible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Offset? originOffset = MatrixUtils.getAsTranslation(transform);
|
final Offset? originOffset = MatrixUtils.getAsTranslation(transform);
|
||||||
|
@ -15,6 +15,7 @@ import 'binding.dart';
|
|||||||
import 'debug.dart';
|
import 'debug.dart';
|
||||||
import 'framework.dart';
|
import 'framework.dart';
|
||||||
import 'localizations.dart';
|
import 'localizations.dart';
|
||||||
|
import 'visibility.dart';
|
||||||
import 'widget_span.dart';
|
import 'widget_span.dart';
|
||||||
|
|
||||||
export 'package:flutter/animation.dart';
|
export 'package:flutter/animation.dart';
|
||||||
@ -3962,12 +3963,80 @@ class Stack extends MultiChildRenderObjectWidget {
|
|||||||
///
|
///
|
||||||
/// * [Stack], for more details about stacks.
|
/// * [Stack], for more details about stacks.
|
||||||
/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
|
/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
|
||||||
class IndexedStack extends Stack {
|
class IndexedStack extends StatelessWidget {
|
||||||
/// Creates a [Stack] widget that paints a single child.
|
/// Creates a [Stack] widget that paints a single child.
|
||||||
///
|
///
|
||||||
/// The [index] argument must not be null.
|
/// The [index] argument must not be null.
|
||||||
const IndexedStack({
|
const IndexedStack({
|
||||||
super.key,
|
super.key,
|
||||||
|
this.alignment = AlignmentDirectional.topStart,
|
||||||
|
this.textDirection,
|
||||||
|
this.clipBehavior = Clip.hardEdge,
|
||||||
|
this.sizing = StackFit.loose,
|
||||||
|
this.index = 0,
|
||||||
|
this.children = const <Widget>[],
|
||||||
|
});
|
||||||
|
|
||||||
|
/// How to align the non-positioned and partially-positioned children in the
|
||||||
|
/// stack.
|
||||||
|
///
|
||||||
|
/// Defaults to [AlignmentDirectional.topStart].
|
||||||
|
///
|
||||||
|
/// See [Stack.alignment] for more information.
|
||||||
|
final AlignmentGeometry alignment;
|
||||||
|
|
||||||
|
/// The text direction with which to resolve [alignment].
|
||||||
|
///
|
||||||
|
/// Defaults to the ambient [Directionality].
|
||||||
|
final TextDirection? textDirection;
|
||||||
|
|
||||||
|
/// {@macro flutter.material.Material.clipBehavior}
|
||||||
|
///
|
||||||
|
/// Defaults to [Clip.hardEdge].
|
||||||
|
final Clip clipBehavior;
|
||||||
|
|
||||||
|
/// How to size the non-positioned children in the stack.
|
||||||
|
///
|
||||||
|
/// Defaults to [StackFit.loose].
|
||||||
|
///
|
||||||
|
/// See [Stack.fit] for more information.
|
||||||
|
final StackFit sizing;
|
||||||
|
|
||||||
|
/// The index of the child to show.
|
||||||
|
///
|
||||||
|
/// If this is null, none of the children will be shown.
|
||||||
|
final int? index;
|
||||||
|
|
||||||
|
/// The child widgets of the stack.
|
||||||
|
///
|
||||||
|
/// Only the child at index [index] will be shown.
|
||||||
|
///
|
||||||
|
/// See [Stack.children] for more information.
|
||||||
|
final List<Widget> children;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final List<Widget> wrappedChildren = List<Widget>.generate(children.length, (int i) {
|
||||||
|
return Visibility.maintain(
|
||||||
|
visible: i == index,
|
||||||
|
child: children[i],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return _RawIndexedStack(
|
||||||
|
alignment: alignment,
|
||||||
|
textDirection: textDirection,
|
||||||
|
clipBehavior: clipBehavior,
|
||||||
|
sizing: sizing,
|
||||||
|
index: index,
|
||||||
|
children: wrappedChildren,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The render object widget that backs [IndexedStack].
|
||||||
|
class _RawIndexedStack extends Stack {
|
||||||
|
/// Creates a [Stack] widget that paints a single child.
|
||||||
|
const _RawIndexedStack({
|
||||||
super.alignment,
|
super.alignment,
|
||||||
super.textDirection,
|
super.textDirection,
|
||||||
super.clipBehavior,
|
super.clipBehavior,
|
||||||
@ -3984,7 +4053,7 @@ class IndexedStack extends Stack {
|
|||||||
assert(_debugCheckHasDirectionality(context));
|
assert(_debugCheckHasDirectionality(context));
|
||||||
return RenderIndexedStack(
|
return RenderIndexedStack(
|
||||||
index: index,
|
index: index,
|
||||||
fit:fit,
|
fit: fit,
|
||||||
clipBehavior: clipBehavior,
|
clipBehavior: clipBehavior,
|
||||||
alignment: alignment,
|
alignment: alignment,
|
||||||
textDirection: textDirection ?? Directionality.maybeOf(context),
|
textDirection: textDirection ?? Directionality.maybeOf(context),
|
||||||
|
@ -223,10 +223,37 @@ class Visibility extends StatelessWidget {
|
|||||||
/// objects, to be immediately created if [visible] is true).
|
/// objects, to be immediately created if [visible] is true).
|
||||||
final bool maintainInteractivity;
|
final bool maintainInteractivity;
|
||||||
|
|
||||||
|
/// Tells the visibility state of an element in the tree based off its
|
||||||
|
/// ancestor [Visibility] elements.
|
||||||
|
///
|
||||||
|
/// If there's one or more [Visibility] widgets in the ancestor tree, this
|
||||||
|
/// will return true if and only if all of those widgets have [visible] set
|
||||||
|
/// to true. If there is no [Visibility] widget in the ancestor tree of the
|
||||||
|
/// specified build context, this will return true.
|
||||||
|
///
|
||||||
|
/// This will register a dependency from the specified context on any
|
||||||
|
/// [Visibility] elements in the ancestor tree, such that if any of their
|
||||||
|
/// visibilities changes, the specified context will be rebuilt.
|
||||||
|
static bool of(BuildContext context) {
|
||||||
|
bool isVisible = true;
|
||||||
|
BuildContext ancestorContext = context;
|
||||||
|
InheritedElement? ancestor = ancestorContext.getElementForInheritedWidgetOfExactType<_VisibilityScope>();
|
||||||
|
while (isVisible && ancestor != null) {
|
||||||
|
final _VisibilityScope scope = context.dependOnInheritedElement(ancestor) as _VisibilityScope;
|
||||||
|
isVisible = scope.isVisible;
|
||||||
|
ancestor.visitAncestorElements((Element parent) {
|
||||||
|
ancestorContext = parent;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
ancestor = ancestorContext.getElementForInheritedWidgetOfExactType<_VisibilityScope>();
|
||||||
|
}
|
||||||
|
return isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
Widget result = child;
|
||||||
if (maintainSize) {
|
if (maintainSize) {
|
||||||
Widget result = child;
|
|
||||||
if (!maintainInteractivity) {
|
if (!maintainInteractivity) {
|
||||||
result = IgnorePointer(
|
result = IgnorePointer(
|
||||||
ignoring: !visible,
|
ignoring: !visible,
|
||||||
@ -234,28 +261,30 @@ class Visibility extends StatelessWidget {
|
|||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return _Visibility(
|
result = _Visibility(
|
||||||
visible: visible,
|
visible: visible,
|
||||||
maintainSemantics: maintainSemantics,
|
maintainSemantics: maintainSemantics,
|
||||||
child: result,
|
child: result,
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
assert(!maintainInteractivity);
|
assert(!maintainInteractivity);
|
||||||
assert(!maintainSemantics);
|
assert(!maintainSemantics);
|
||||||
assert(!maintainSize);
|
assert(!maintainSize);
|
||||||
if (maintainState) {
|
if (maintainState) {
|
||||||
Widget result = child;
|
if (!maintainAnimation) {
|
||||||
if (!maintainAnimation) {
|
result = TickerMode(enabled: visible, child: child);
|
||||||
result = TickerMode(enabled: visible, child: child);
|
}
|
||||||
|
result = Offstage(
|
||||||
|
offstage: !visible,
|
||||||
|
child: result,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert(!maintainAnimation);
|
||||||
|
assert(!maintainState);
|
||||||
|
result = visible ? child : replacement;
|
||||||
}
|
}
|
||||||
return Offstage(
|
|
||||||
offstage: !visible,
|
|
||||||
child: result,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
assert(!maintainAnimation);
|
return _VisibilityScope(isVisible: visible, child: result);
|
||||||
assert(!maintainState);
|
|
||||||
return visible ? child : replacement;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -270,6 +299,18 @@ class Visibility extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Inherited widget that allows descendants to find their visibility status.
|
||||||
|
class _VisibilityScope extends InheritedWidget {
|
||||||
|
const _VisibilityScope({required this.isVisible, required super.child});
|
||||||
|
|
||||||
|
final bool isVisible;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotify(_VisibilityScope old) {
|
||||||
|
return isVisible != old.isVisible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether to show or hide a sliver child.
|
/// Whether to show or hide a sliver child.
|
||||||
///
|
///
|
||||||
/// By default, the [visible] property controls whether the [sliver] is included
|
/// By default, the [visible] property controls whether the [sliver] is included
|
||||||
|
@ -568,6 +568,28 @@ void main() {
|
|||||||
..circle(x: 50.0, y: 50.0, color: splashColor)
|
..circle(x: 50.0, y: 50.0, color: splashColor)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Ink with isVisible=false does not paint', (WidgetTester tester) async {
|
||||||
|
const Color testColor = Color(0xffff1234);
|
||||||
|
Widget inkWidget({required bool isVisible}) {
|
||||||
|
return Material(
|
||||||
|
child: Visibility.maintain(
|
||||||
|
visible: isVisible,
|
||||||
|
child: Ink(
|
||||||
|
decoration: const BoxDecoration(color: testColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(inkWidget(isVisible: true));
|
||||||
|
RenderBox box = tester.renderObject(find.byType(Material));
|
||||||
|
expect(box, paints..rect(color: testColor));
|
||||||
|
|
||||||
|
await tester.pumpWidget(inkWidget(isVisible: false));
|
||||||
|
box = tester.renderObject(find.byType(Material));
|
||||||
|
expect(box, isNot(paints..rect(color: testColor)));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class _InkRippleFactory extends InteractiveInkFeatureFactory {
|
class _InkRippleFactory extends InteractiveInkFeatureFactory {
|
||||||
|
@ -308,6 +308,41 @@ void main() {
|
|||||||
expect(itemsTapped, <int>[2]);
|
expect(itemsTapped, <int>[2]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('IndexedStack sets non-selected indexes to visible=false', (WidgetTester tester) async {
|
||||||
|
Widget buildStack({required int itemCount, required int? selectedIndex}) {
|
||||||
|
final List<Widget> children = List<Widget>.generate(itemCount, (int i) {
|
||||||
|
return _ShowVisibility(index: i);
|
||||||
|
});
|
||||||
|
return Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: IndexedStack(
|
||||||
|
index: selectedIndex,
|
||||||
|
children: children,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildStack(itemCount: 3, selectedIndex: null));
|
||||||
|
expect(find.text('index 0 is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
expect(find.text('index 1 is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
expect(find.text('index 2 is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildStack(itemCount: 3, selectedIndex: 0));
|
||||||
|
expect(find.text('index 0 is visible ? true', skipOffstage: false), findsOneWidget);
|
||||||
|
expect(find.text('index 1 is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
expect(find.text('index 2 is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildStack(itemCount: 3, selectedIndex: 1));
|
||||||
|
expect(find.text('index 0 is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
expect(find.text('index 1 is visible ? true', skipOffstage: false), findsOneWidget);
|
||||||
|
expect(find.text('index 2 is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildStack(itemCount: 3, selectedIndex: 2));
|
||||||
|
expect(find.text('index 0 is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
expect(find.text('index 1 is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
expect(find.text('index 2 is visible ? true', skipOffstage: false), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('Can set width and height', (WidgetTester tester) async {
|
testWidgets('Can set width and height', (WidgetTester tester) async {
|
||||||
const Key key = Key('container');
|
const Key key = Key('container');
|
||||||
|
|
||||||
@ -866,3 +901,14 @@ void main() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _ShowVisibility extends StatelessWidget {
|
||||||
|
const _ShowVisibility({required this.index});
|
||||||
|
|
||||||
|
final int index;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text('index $index is visible ? ${Visibility.of(context)}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -471,4 +471,108 @@ void main() {
|
|||||||
expect(tester.layers, isNot(contains(isA<OpacityLayer>())));
|
expect(tester.layers, isNot(contains(isA<OpacityLayer>())));
|
||||||
expect(tester.layers.last, isA<PictureLayer>());
|
expect(tester.layers.last, isA<PictureLayer>());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Visibility.of returns correct value', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: _ShowVisibility(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(find.text('is visible ? true', skipOffstage: false), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Visibility(
|
||||||
|
maintainState: true,
|
||||||
|
child: _ShowVisibility(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(find.text('is visible ? true', skipOffstage: false), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Visibility(
|
||||||
|
visible: false,
|
||||||
|
maintainState: true,
|
||||||
|
child: _ShowVisibility(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(find.text('is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Visibility.of works when multiple Visibility widgets are in hierarchy', (WidgetTester tester) async {
|
||||||
|
bool didChangeDependencies = false;
|
||||||
|
void handleDidChangeDependencies() {
|
||||||
|
didChangeDependencies = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget newWidget({required bool ancestorIsVisible, required bool descendantIsVisible}) {
|
||||||
|
return Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Visibility(
|
||||||
|
visible: ancestorIsVisible,
|
||||||
|
maintainState: true,
|
||||||
|
child: Center(
|
||||||
|
child: Visibility(
|
||||||
|
visible: descendantIsVisible,
|
||||||
|
maintainState: true,
|
||||||
|
child: _ShowVisibility(
|
||||||
|
onDidChangeDependencies: handleDidChangeDependencies,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(newWidget(ancestorIsVisible: true, descendantIsVisible: true));
|
||||||
|
expect(didChangeDependencies, isTrue);
|
||||||
|
expect(find.text('is visible ? true', skipOffstage: false), findsOneWidget);
|
||||||
|
didChangeDependencies = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(newWidget(ancestorIsVisible: true, descendantIsVisible: false));
|
||||||
|
expect(didChangeDependencies, isTrue);
|
||||||
|
expect(find.text('is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
didChangeDependencies = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(newWidget(ancestorIsVisible: true, descendantIsVisible: false));
|
||||||
|
expect(didChangeDependencies, isFalse);
|
||||||
|
|
||||||
|
await tester.pumpWidget(newWidget(ancestorIsVisible: false, descendantIsVisible: false));
|
||||||
|
expect(didChangeDependencies, isTrue);
|
||||||
|
didChangeDependencies = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(newWidget(ancestorIsVisible: false, descendantIsVisible: true));
|
||||||
|
expect(didChangeDependencies, isTrue);
|
||||||
|
expect(find.text('is visible ? false', skipOffstage: false), findsOneWidget);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ShowVisibility extends StatefulWidget {
|
||||||
|
const _ShowVisibility({this.onDidChangeDependencies});
|
||||||
|
|
||||||
|
final VoidCallback? onDidChangeDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_ShowVisibility> createState() => _ShowVisibilityState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ShowVisibilityState extends State<_ShowVisibility> {
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
if (widget.onDidChangeDependencies != null) {
|
||||||
|
widget.onDidChangeDependencies!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text('is visible ? ${Visibility.of(context)}');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user