Unverified Commit 4119210e authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[framework] use Visibility instead of Opacity (#112191)

parent 97b53bc9
......@@ -378,9 +378,9 @@ class _CupertinoContextMenuState extends State<CupertinoContextMenu> with Ticker
onTap: _onTap,
child: TickerMode(
enabled: !_childHidden,
child: Opacity(
child: Visibility.maintain(
key: _childGlobalKey,
opacity: _childHidden ? 0.0 : 1.0,
visible: !_childHidden,
child: widget.child,
),
),
......
......@@ -728,9 +728,8 @@ class _Label extends StatelessWidget {
if (!showUnselectedLabels && !showSelectedLabels) {
// Never show any labels.
text = Opacity(
alwaysIncludeSemantics: true,
opacity: 0.0,
text = Visibility.maintain(
visible: false,
child: text,
);
} else if (!showUnselectedLabels) {
......
......@@ -619,9 +619,8 @@ class _RailDestination extends StatelessWidget {
SizedBox(
width: 0,
height: 0,
child: Opacity(
alwaysIncludeSemantics: true,
opacity: 0.0,
child: Visibility.maintain(
visible: false,
child: label,
),
),
......
......@@ -289,7 +289,9 @@ class Directionality extends _UbiquitousInheritedWidget {
///
/// * [Visibility], which can hide a child more efficiently (albeit less
/// subtly, because it is either visible or hidden, rather than allowing
/// fractional opacity values).
/// fractional opacity values). Specifically, the [Visibility.maintain]
/// constructor is equivalent to using an opacity widget with values of
/// `0.0` or `1.0`.
/// * [ShaderMask], which can apply more elaborate effects to its child.
/// * [Transform], which applies an arbitrary transform to its child widget at
/// paint time.
......
......@@ -1656,6 +1656,11 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
/// RenderBox layout protocol.
/// * [AnimatedOpacity], which uses an animation internally to efficiently
/// animate [Opacity].
/// * [SliverVisibility], which can hide a child more efficiently (albeit less
/// subtly, because it is either visible or hidden, rather than allowing
/// fractional opacity values). Specifically, the [SliverVisibility.maintain]
/// constructor is equivalent to using a sliver opacity widget with values of
/// `0.0` or `1.0`.
class SliverOpacity extends SingleChildRenderObjectWidget {
/// Creates a sliver that makes its sliver child partially transparent.
///
......
......@@ -85,6 +85,28 @@ class Visibility extends StatelessWidget {
'Cannot maintain interactivity if size is not maintained.',
);
/// Control whether the given [child] is [visible].
///
/// The [child] and [replacement] arguments must not be null.
///
/// This is equivalent to the default [Visibility] constructor with all
/// "maintain" fields set to true. This constructor should be used in place of
/// an [Opacity] widget that only takes on values of `0.0` or `1.0`, as it
/// avoids extra compositing when fully opaque.
const Visibility.maintain({
super.key,
required this.child,
this.replacement = const SizedBox.shrink(),
this.visible = true,
}) : assert(child != null),
assert(replacement != null),
assert(visible != null),
maintainState = true,
maintainAnimation = true,
maintainSize = true,
maintainSemantics = true,
maintainInteractivity = true;
/// The widget to show or hide, as controlled by [visible].
///
/// {@macro flutter.widgets.ProxyWidget.child}
......@@ -332,6 +354,28 @@ class SliverVisibility extends StatelessWidget {
'Cannot maintain interactivity if size is not maintained.',
);
/// Control whether the given [sliver] is [visible].
///
/// The [sliver] and [replacementSliver] arguments must not be null.
///
/// This is equivalent to the default [SliverVisibility] constructor with all
/// "maintain" fields set to true. This constructor should be used in place of
/// a [SliverOpacity] widget that only takes on values of `0.0` or `1.0`, as it
/// avoids extra compositing when fully opaque.
const SliverVisibility.maintain({
super.key,
required this.sliver,
this.replacementSliver = const SliverToBoxAdapter(),
this.visible = true,
}) : assert(sliver != null),
assert(replacementSliver != null),
assert(visible != null),
maintainState = true,
maintainAnimation = true,
maintainSize = true,
maintainSemantics = true,
maintainInteractivity = true;
/// The sliver to show or hide, as controlled by [visible].
final Widget sliver;
......
......@@ -1971,8 +1971,8 @@ void main() {
await tester.pumpWidget(widget);
expect(find.text('Red'), findsOneWidget);
expect(find.text('Green'), findsOneWidget);
expect(tester.widget<Opacity>(find.byType(Opacity).first).opacity, 0.0);
expect(tester.widget<Opacity>(find.byType(Opacity).last).opacity, 0.0);
expect(tester.widget<Visibility>(find.byType(Visibility).first).visible, false);
expect(tester.widget<Visibility>(find.byType(Visibility).last).visible, false);
},
);
......@@ -2009,8 +2009,8 @@ void main() {
);
expect(find.text('Red'), findsOneWidget);
expect(find.text('Green'), findsOneWidget);
expect(tester.widget<Opacity>(find.byType(Opacity).first).opacity, 0.0);
expect(tester.widget<Opacity>(find.byType(Opacity).last).opacity, 0.0);
expect(tester.widget<Visibility>(find.byType(Visibility).first).visible, false);
expect(tester.widget<Visibility>(find.byType(Visibility).last).visible, false);
},
);
......
......@@ -359,14 +359,14 @@ void main() {
);
final Finder findOpacity = find.descendant(
final Finder findVisibility = find.descendant(
of: find.byType(BottomNavigationBar),
matching: find.byType(Opacity),
matching: find.byType(Visibility),
);
expect(findOpacity, findsNWidgets(2));
expect(tester.widget<Opacity>(findOpacity.at(0)).opacity, 0.0);
expect(tester.widget<Opacity>(findOpacity.at(1)).opacity, 0.0);
expect(findVisibility, findsNWidgets(2));
expect(tester.widget<Visibility>(findVisibility.at(0)).visible, false);
expect(tester.widget<Visibility>(findVisibility.at(1)).visible, false);
});
testWidgets('BottomNavigationBarTheme can be used to hide selected labels', (WidgetTester tester) async {
......
......@@ -4693,14 +4693,14 @@ Finder _opacityAboveLabel(String text) {
// Only valid when labelType != all.
double? _labelOpacity(WidgetTester tester, String text) {
// We search for both Opacity and FadeTransition since in some
// We search for both Visibility and FadeTransition since in some
// cases opacity is animated, in other it's not.
final Iterable<Opacity> opacityWidgets = tester.widgetList<Opacity>(find.ancestor(
final Iterable<Visibility> visibilityWidgets = tester.widgetList<Visibility>(find.ancestor(
of: find.text(text),
matching: find.byType(Opacity),
matching: find.byType(Visibility),
));
if (opacityWidgets.isNotEmpty) {
return opacityWidgets.single.opacity;
if (visibilityWidgets.isNotEmpty) {
return visibilityWidgets.single.visible ? 1.0 : 0.0;
}
final FadeTransition fadeTransitionWidget = tester.widget<FadeTransition>(
......
......@@ -363,27 +363,27 @@ Align _destinationsAlign(WidgetTester tester) {
}
NavigationRailLabelType _labelType(WidgetTester tester) {
if (_opacityAboveLabel('Abc').evaluate().isNotEmpty && _opacityAboveLabel('Def').evaluate().isNotEmpty) {
return _labelOpacity(tester, 'Abc') == 1 ? NavigationRailLabelType.selected : NavigationRailLabelType.none;
if (_visibilityAboveLabel('Abc').evaluate().isNotEmpty && _visibilityAboveLabel('Def').evaluate().isNotEmpty) {
return _labelVisibility(tester, 'Abc') ? NavigationRailLabelType.selected : NavigationRailLabelType.none;
} else {
return NavigationRailLabelType.all;
}
}
Finder _opacityAboveLabel(String text) {
Finder _visibilityAboveLabel(String text) {
return find.ancestor(
of: find.text(text),
matching: find.byType(Opacity),
matching: find.byType(Visibility),
);
}
// Only valid when labelType != all.
double _labelOpacity(WidgetTester tester, String text) {
final Opacity opacityWidget = tester.widget<Opacity>(
bool _labelVisibility(WidgetTester tester, String text) {
final Visibility visibilityWidget = tester.widget<Visibility>(
find.ancestor(
of: find.text(text),
matching: find.byType(Opacity),
matching: find.byType(Visibility),
),
);
return opacityWidget.opacity;
return visibilityWidget.visible;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment