Make BottomNavBar accessible (#15211)
This commit is contained in:
parent
0edea88745
commit
86be138d9c
@ -13,6 +13,7 @@ import 'colors.dart';
|
|||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
import 'ink_well.dart';
|
import 'ink_well.dart';
|
||||||
import 'material.dart';
|
import 'material.dart';
|
||||||
|
import 'material_localizations.dart';
|
||||||
import 'theme.dart';
|
import 'theme.dart';
|
||||||
import 'typography.dart';
|
import 'typography.dart';
|
||||||
|
|
||||||
@ -129,9 +130,11 @@ class _BottomNavigationTile extends StatelessWidget {
|
|||||||
this.iconSize, {
|
this.iconSize, {
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.colorTween,
|
this.colorTween,
|
||||||
this.flex
|
this.flex,
|
||||||
|
this.selected: false,
|
||||||
|
this.indexLabel,
|
||||||
}
|
}
|
||||||
);
|
): assert(selected != null);
|
||||||
|
|
||||||
final BottomNavigationBarType type;
|
final BottomNavigationBarType type;
|
||||||
final BottomNavigationBarItem item;
|
final BottomNavigationBarItem item;
|
||||||
@ -140,6 +143,8 @@ class _BottomNavigationTile extends StatelessWidget {
|
|||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
final ColorTween colorTween;
|
final ColorTween colorTween;
|
||||||
final double flex;
|
final double flex;
|
||||||
|
final bool selected;
|
||||||
|
final String indexLabel;
|
||||||
|
|
||||||
Widget _buildIcon() {
|
Widget _buildIcon() {
|
||||||
double tweenStart;
|
double tweenStart;
|
||||||
@ -255,15 +260,26 @@ class _BottomNavigationTile extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
return new Expanded(
|
return new Expanded(
|
||||||
flex: size,
|
flex: size,
|
||||||
child: new InkResponse(
|
child: new Semantics(
|
||||||
onTap: onTap,
|
container: true,
|
||||||
child: new Column(
|
selected: selected,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
child: new Stack(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
_buildIcon(),
|
new InkResponse(
|
||||||
label,
|
onTap: onTap,
|
||||||
|
child: new Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
_buildIcon(),
|
||||||
|
label,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
new Semantics(
|
||||||
|
label: indexLabel,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -368,6 +384,8 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _createTiles() {
|
List<Widget> _createTiles() {
|
||||||
|
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||||
|
assert(localizations != null);
|
||||||
final List<Widget> children = <Widget>[];
|
final List<Widget> children = <Widget>[];
|
||||||
switch (widget.type) {
|
switch (widget.type) {
|
||||||
case BottomNavigationBarType.fixed:
|
case BottomNavigationBarType.fixed:
|
||||||
@ -398,6 +416,8 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
|||||||
widget.onTap(i);
|
widget.onTap(i);
|
||||||
},
|
},
|
||||||
colorTween: colorTween,
|
colorTween: colorTween,
|
||||||
|
selected: i == widget.currentIndex,
|
||||||
|
indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: widget.items.length),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -415,7 +435,9 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
|||||||
widget.onTap(i);
|
widget.onTap(i);
|
||||||
},
|
},
|
||||||
flex: _evaluateFlex(_animations[i]),
|
flex: _evaluateFlex(_animations[i]),
|
||||||
),
|
selected: i == widget.currentIndex,
|
||||||
|
indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: widget.items.length),
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
import '../rendering/mock_canvas.dart';
|
import '../rendering/mock_canvas.dart';
|
||||||
|
import '../widgets/semantics_tester.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('BottomNavigationBar callback test', (WidgetTester tester) async {
|
testWidgets('BottomNavigationBar callback test', (WidgetTester tester) async {
|
||||||
@ -483,17 +486,85 @@ void main() {
|
|||||||
await tester.pump(const Duration(milliseconds: 20));
|
await tester.pump(const Duration(milliseconds: 20));
|
||||||
expect(box, paints..circle(x: 600.0)..circle(x: 200.0)..circle(x: 600.0));
|
expect(box, paints..circle(x: 600.0)..circle(x: 200.0)..circle(x: 600.0));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('BottomNavigationBar semantics', (WidgetTester tester) async {
|
||||||
|
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
boilerplate(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
bottomNavigationBar: new BottomNavigationBar(
|
||||||
|
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'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO(goderbauer): traversal order is incorrect, https://github.com/flutter/flutter/issues/14375
|
||||||
|
final TestSemantics expected = new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics(
|
||||||
|
id: 1,
|
||||||
|
flags: <SemanticsFlag>[SemanticsFlag.isSelected],
|
||||||
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||||
|
label: 'AC\nTab 1 of 3',
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
nextNodeId: -1,
|
||||||
|
previousNodeId: 3, // Should be 2
|
||||||
|
),
|
||||||
|
new TestSemantics(
|
||||||
|
id: 2,
|
||||||
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||||
|
label: 'Alarm\nTab 2 of 3',
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
nextNodeId: 3,
|
||||||
|
previousNodeId: -1, // Should be 1
|
||||||
|
),
|
||||||
|
new TestSemantics(
|
||||||
|
id: 3,
|
||||||
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||||
|
label: 'Hot Tub\nTab 3 of 3',
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
nextNodeId: 1, // Should be -1
|
||||||
|
previousNodeId: 2,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
expect(semantics, hasSemantics(expected, ignoreTransform: true, ignoreRect: true));
|
||||||
|
|
||||||
|
semantics.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget boilerplate({ Widget bottomNavigationBar, @required TextDirection textDirection }) {
|
Widget boilerplate({ Widget bottomNavigationBar, @required TextDirection textDirection }) {
|
||||||
assert(textDirection != null);
|
assert(textDirection != null);
|
||||||
return new Directionality(
|
return new Localizations(
|
||||||
textDirection: textDirection,
|
locale: const Locale('en', 'US'),
|
||||||
child: new MediaQuery(
|
delegates: <LocalizationsDelegate<dynamic>>[
|
||||||
data: const MediaQueryData(),
|
DefaultMaterialLocalizations.delegate,
|
||||||
child: new Material(
|
DefaultWidgetsLocalizations.delegate,
|
||||||
child: new Scaffold(
|
],
|
||||||
bottomNavigationBar: bottomNavigationBar,
|
child: new Directionality(
|
||||||
|
textDirection: textDirection,
|
||||||
|
child: new MediaQuery(
|
||||||
|
data: const MediaQueryData(),
|
||||||
|
child: new Material(
|
||||||
|
child: new Scaffold(
|
||||||
|
bottomNavigationBar: bottomNavigationBar,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user