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),
|
||||
),
|
||||
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(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user