make sure bottom nav bar always contributes labels (#19934)
This commit is contained in:
parent
3a6228bead
commit
5b30b393a8
@ -242,6 +242,7 @@ class _BottomNavigationTile extends StatelessWidget {
|
|||||||
).evaluate(animation),
|
).evaluate(animation),
|
||||||
),
|
),
|
||||||
child: new FadeTransition(
|
child: new FadeTransition(
|
||||||
|
alwaysIncludeSemantics: true,
|
||||||
opacity: animation,
|
opacity: animation,
|
||||||
child: DefaultTextStyle.merge(
|
child: DefaultTextStyle.merge(
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
|
@ -792,7 +792,14 @@ class RenderAnimatedOpacity extends RenderProxyBox {
|
|||||||
/// Creates a partially transparent render object.
|
/// Creates a partially transparent render object.
|
||||||
///
|
///
|
||||||
/// The [opacity] argument must not be null.
|
/// 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;
|
this.opacity = opacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -823,6 +830,18 @@ class RenderAnimatedOpacity extends RenderProxyBox {
|
|||||||
_updateOpacity();
|
_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
|
@override
|
||||||
void attach(PipelineOwner owner) {
|
void attach(PipelineOwner owner) {
|
||||||
super.attach(owner);
|
super.attach(owner);
|
||||||
@ -866,7 +885,7 @@ class RenderAnimatedOpacity extends RenderProxyBox {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void visitChildrenForSemantics(RenderObjectVisitor visitor) {
|
void visitChildrenForSemantics(RenderObjectVisitor visitor) {
|
||||||
if (child != null && _alpha != 0)
|
if (child != null && (_alpha != 0 || alwaysIncludeSemantics))
|
||||||
visitor(child);
|
visitor(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +342,7 @@ class FadeTransition extends SingleChildRenderObjectWidget {
|
|||||||
Key key,
|
Key key,
|
||||||
@required this.opacity,
|
@required this.opacity,
|
||||||
Widget child,
|
Widget child,
|
||||||
|
this.alwaysIncludeSemantics = false,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The animation that controls the opacity of the child.
|
/// The animation that controls the opacity of the child.
|
||||||
@ -352,17 +353,29 @@ class FadeTransition extends SingleChildRenderObjectWidget {
|
|||||||
/// completely transparent.
|
/// completely transparent.
|
||||||
final Animation<double> opacity;
|
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
|
@override
|
||||||
RenderAnimatedOpacity createRenderObject(BuildContext context) {
|
RenderAnimatedOpacity createRenderObject(BuildContext context) {
|
||||||
return new RenderAnimatedOpacity(
|
return new RenderAnimatedOpacity(
|
||||||
opacity: opacity,
|
opacity: opacity,
|
||||||
|
alwaysIncludeSemantics: alwaysIncludeSemantics,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void updateRenderObject(BuildContext context, RenderAnimatedOpacity renderObject) {
|
void updateRenderObject(BuildContext context, RenderAnimatedOpacity renderObject) {
|
||||||
renderObject
|
renderObject
|
||||||
..opacity = opacity;
|
..opacity = opacity
|
||||||
|
..alwaysIncludeSemantics = alwaysIncludeSemantics;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -539,7 +539,7 @@ void main() {
|
|||||||
expect(find.byKey(stroked), findsOneWidget);
|
expect(find.byKey(stroked), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('BottomNavigationBar semantics', (WidgetTester tester) async {
|
testWidgets('BottomNavigationBar.fixed semantics', (WidgetTester tester) async {
|
||||||
final SemanticsTester semantics = new SemanticsTester(tester);
|
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
@ -567,13 +567,10 @@ void main() {
|
|||||||
final TestSemantics expected = new TestSemantics.root(
|
final TestSemantics expected = new TestSemantics.root(
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 1,
|
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 2,
|
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 3,
|
|
||||||
flags: <SemanticsFlag>[
|
flags: <SemanticsFlag>[
|
||||||
SemanticsFlag.isSelected,
|
SemanticsFlag.isSelected,
|
||||||
SemanticsFlag.isHeader,
|
SemanticsFlag.isHeader,
|
||||||
@ -583,7 +580,6 @@ void main() {
|
|||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
),
|
),
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 4,
|
|
||||||
flags: <SemanticsFlag>[
|
flags: <SemanticsFlag>[
|
||||||
SemanticsFlag.isHeader,
|
SemanticsFlag.isHeader,
|
||||||
],
|
],
|
||||||
@ -592,7 +588,6 @@ void main() {
|
|||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
),
|
),
|
||||||
new TestSemantics(
|
new TestSemantics(
|
||||||
id: 5,
|
|
||||||
flags: <SemanticsFlag>[
|
flags: <SemanticsFlag>[
|
||||||
SemanticsFlag.isHeader,
|
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();
|
semantics.dispose();
|
||||||
});
|
});
|
||||||
|
@ -219,6 +219,7 @@ void main() {
|
|||||||
)..value = 0.0;
|
)..value = 0.0;
|
||||||
|
|
||||||
final RenderAnimatedOpacity renderAnimatedOpacity = new RenderAnimatedOpacity(
|
final RenderAnimatedOpacity renderAnimatedOpacity = new RenderAnimatedOpacity(
|
||||||
|
alwaysIncludeSemantics: false,
|
||||||
opacity: opacityAnimation,
|
opacity: opacityAnimation,
|
||||||
child: new RenderSizedBox(const Size(1.0, 1.0)), // size doesn't matter
|
child: new RenderSizedBox(const Size(1.0, 1.0)), // size doesn't matter
|
||||||
);
|
);
|
||||||
@ -233,6 +234,7 @@ void main() {
|
|||||||
)..value = 1.0;
|
)..value = 1.0;
|
||||||
|
|
||||||
final RenderAnimatedOpacity renderAnimatedOpacity = new RenderAnimatedOpacity(
|
final RenderAnimatedOpacity renderAnimatedOpacity = new RenderAnimatedOpacity(
|
||||||
|
alwaysIncludeSemantics: false,
|
||||||
opacity: opacityAnimation,
|
opacity: opacityAnimation,
|
||||||
child: new RenderSizedBox(const Size(1.0, 1.0)), // size doesn't matter
|
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', () {
|
test('RenderOpacity and children and semantics', () {
|
||||||
final AnimationController controller = new AnimationController(vsync: const TestVSync());
|
final AnimationController controller = new AnimationController(vsync: const TestVSync());
|
||||||
final RenderAnimatedOpacity box = new RenderAnimatedOpacity(
|
final RenderAnimatedOpacity box = new RenderAnimatedOpacity(
|
||||||
|
alwaysIncludeSemantics: false,
|
||||||
opacity: controller,
|
opacity: controller,
|
||||||
child: new RenderParagraph(
|
child: new RenderParagraph(
|
||||||
const TextSpan(),
|
const TextSpan(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user