Unverified Commit 5b30b393 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

make sure bottom nav bar always contributes labels (#19934)

parent 3a6228be
......@@ -242,6 +242,7 @@ class _BottomNavigationTile extends StatelessWidget {
).evaluate(animation),
),
child: new FadeTransition(
alwaysIncludeSemantics: true,
opacity: animation,
child: DefaultTextStyle.merge(
style: const TextStyle(
......
......@@ -792,7 +792,14 @@ class RenderAnimatedOpacity extends RenderProxyBox {
/// Creates a partially transparent render object.
///
/// The [opacity] argument must not be null.
RenderAnimatedOpacity({ @required Animation<double> opacity, RenderBox child }) : super(child) {
RenderAnimatedOpacity({
@required Animation<double> opacity,
bool alwaysIncludeSemantics = false,
RenderBox child,
}) : assert(opacity != null),
assert(alwaysIncludeSemantics != null),
_alwaysIncludeSemantics = alwaysIncludeSemantics,
super(child) {
this.opacity = opacity;
}
......@@ -823,6 +830,18 @@ class RenderAnimatedOpacity extends RenderProxyBox {
_updateOpacity();
}
/// Whether child semantics are included regardless of the opacity.
///
/// Defaults to false.
bool get alwaysIncludeSemantics => _alwaysIncludeSemantics;
bool _alwaysIncludeSemantics;
set alwaysIncludeSemantics(bool value) {
if (value == _alwaysIncludeSemantics)
return;
_alwaysIncludeSemantics = value;
markNeedsSemanticsUpdate();
}
@override
void attach(PipelineOwner owner) {
super.attach(owner);
......@@ -866,7 +885,7 @@ class RenderAnimatedOpacity extends RenderProxyBox {
@override
void visitChildrenForSemantics(RenderObjectVisitor visitor) {
if (child != null && _alpha != 0)
if (child != null && (_alpha != 0 || alwaysIncludeSemantics))
visitor(child);
}
......
......@@ -342,6 +342,7 @@ class FadeTransition extends SingleChildRenderObjectWidget {
Key key,
@required this.opacity,
Widget child,
this.alwaysIncludeSemantics = false,
}) : super(key: key, child: child);
/// The animation that controls the opacity of the child.
......@@ -352,17 +353,29 @@ class FadeTransition extends SingleChildRenderObjectWidget {
/// completely transparent.
final Animation<double> opacity;
/// Whether the semantic information of the children is always included.
///
/// Defaults to false.
///
/// When true, regardless of the opacity settings the child semantic
/// information is exposed as if the widget were fully visible. This is
/// useful in cases where labels may be hidden during animations that
/// would otherwise contribute relevant semantics.
final bool alwaysIncludeSemantics;
@override
RenderAnimatedOpacity createRenderObject(BuildContext context) {
return new RenderAnimatedOpacity(
opacity: opacity,
alwaysIncludeSemantics: alwaysIncludeSemantics,
);
}
@override
void updateRenderObject(BuildContext context, RenderAnimatedOpacity renderObject) {
renderObject
..opacity = opacity;
..opacity = opacity
..alwaysIncludeSemantics = alwaysIncludeSemantics;
}
@override
......
......@@ -539,7 +539,7 @@ void main() {
expect(find.byKey(stroked), findsOneWidget);
});
testWidgets('BottomNavigationBar semantics', (WidgetTester tester) async {
testWidgets('BottomNavigationBar.fixed semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(
......@@ -567,13 +567,10 @@ void main() {
final TestSemantics expected = new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics(
id: 1,
children: <TestSemantics>[
new TestSemantics(
id: 2,
children: <TestSemantics>[
new TestSemantics(
id: 3,
flags: <SemanticsFlag>[
SemanticsFlag.isSelected,
SemanticsFlag.isHeader,
......@@ -583,7 +580,6 @@ void main() {
textDirection: TextDirection.ltr,
),
new TestSemantics(
id: 4,
flags: <SemanticsFlag>[
SemanticsFlag.isHeader,
],
......@@ -592,7 +588,6 @@ void main() {
textDirection: TextDirection.ltr,
),
new TestSemantics(
id: 5,
flags: <SemanticsFlag>[
SemanticsFlag.isHeader,
],
......@@ -606,7 +601,75 @@ void main() {
),
],
);
expect(semantics, hasSemantics(expected, ignoreTransform: true, ignoreRect: true));
expect(semantics, hasSemantics(expected, ignoreId: true, ignoreTransform: true, ignoreRect: true));
semantics.dispose();
});
testWidgets('BottomNavigationBar.shifting semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(
boilerplate(
textDirection: TextDirection.ltr,
bottomNavigationBar: new BottomNavigationBar(
type: BottomNavigationBarType.shifting,
items: const <BottomNavigationBarItem>[
const BottomNavigationBarItem(
icon: const Icon(Icons.ac_unit),
title: const Text('AC'),
),
const BottomNavigationBarItem(
icon: const Icon(Icons.access_alarm),
title: const Text('Alarm'),
),
const BottomNavigationBarItem(
icon: const Icon(Icons.hot_tub),
title: const Text('Hot Tub'),
),
],
),
),
);
final TestSemantics expected = new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics(
children: <TestSemantics>[
new TestSemantics(
children: <TestSemantics>[
new TestSemantics(
flags: <SemanticsFlag>[
SemanticsFlag.isSelected,
SemanticsFlag.isHeader,
],
actions: <SemanticsAction>[SemanticsAction.tap],
label: 'AC\nTab 1 of 3',
textDirection: TextDirection.ltr,
),
new TestSemantics(
flags: <SemanticsFlag>[
SemanticsFlag.isHeader,
],
actions: <SemanticsAction>[SemanticsAction.tap],
label: 'Alarm\nTab 2 of 3',
textDirection: TextDirection.ltr,
),
new TestSemantics(
flags: <SemanticsFlag>[
SemanticsFlag.isHeader,
],
actions: <SemanticsAction>[SemanticsAction.tap],
label: 'Hot Tub\nTab 3 of 3',
textDirection: TextDirection.ltr,
),
],
),
],
),
],
);
expect(semantics, hasSemantics(expected, ignoreId: true, ignoreTransform: true, ignoreRect: true));
semantics.dispose();
});
......
......@@ -219,6 +219,7 @@ void main() {
)..value = 0.0;
final RenderAnimatedOpacity renderAnimatedOpacity = new RenderAnimatedOpacity(
alwaysIncludeSemantics: false,
opacity: opacityAnimation,
child: new RenderSizedBox(const Size(1.0, 1.0)), // size doesn't matter
);
......@@ -233,6 +234,7 @@ void main() {
)..value = 1.0;
final RenderAnimatedOpacity renderAnimatedOpacity = new RenderAnimatedOpacity(
alwaysIncludeSemantics: false,
opacity: opacityAnimation,
child: new RenderSizedBox(const Size(1.0, 1.0)), // size doesn't matter
);
......
......@@ -43,6 +43,7 @@ void main() {
test('RenderOpacity and children and semantics', () {
final AnimationController controller = new AnimationController(vsync: const TestVSync());
final RenderAnimatedOpacity box = new RenderAnimatedOpacity(
alwaysIncludeSemantics: false,
opacity: controller,
child: new RenderParagraph(
const TextSpan(),
......
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