Semantics for CupertinoTabBar (#19924)
This commit is contained in:
parent
5b30b393a8
commit
cb03ca1d9a
@ -156,9 +156,15 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
final List<Widget> result = <Widget>[];
|
||||
|
||||
for (int index = 0; index < items.length; index += 1) {
|
||||
final bool active = index == currentIndex;
|
||||
result.add(
|
||||
_wrapActiveItem(
|
||||
new Expanded(
|
||||
child: new Semantics(
|
||||
selected: active,
|
||||
// TODO(https://github.com/flutter/flutter/issues/13452):
|
||||
// This needs localization support.
|
||||
hint: 'tab, ${index + 1} of ${items.length}',
|
||||
child: new GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: onTap == null ? null : () { onTap(index); },
|
||||
@ -174,7 +180,8 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
active: index == currentIndex,
|
||||
),
|
||||
active: active,
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -183,7 +190,7 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
}
|
||||
|
||||
/// Change the active tab item's icon and title colors to active.
|
||||
Widget _wrapActiveItem(Widget item, { bool active }) {
|
||||
Widget _wrapActiveItem(Widget item, { @required bool active }) {
|
||||
if (!active)
|
||||
return item;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../painting/mocks_for_image_cache.dart';
|
||||
import '../widgets/semantics_tester.dart';
|
||||
|
||||
Future<Null> pumpWidgetWithBoilerplate(WidgetTester tester, Widget widget) async {
|
||||
await tester.pumpWidget(
|
||||
@ -169,4 +170,39 @@ void main() {
|
||||
await tester.tap(find.text('Tab 1'));
|
||||
expect(callbackTab, 0);
|
||||
});
|
||||
|
||||
testWidgets('tabs announce semantics', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||
|
||||
await pumpWidgetWithBoilerplate(tester, new MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: new CupertinoTabBar(
|
||||
items: const <BottomNavigationBarItem>[
|
||||
const BottomNavigationBarItem(
|
||||
icon: const ImageIcon(const TestImageProvider(24, 24)),
|
||||
title: const Text('Tab 1'),
|
||||
),
|
||||
const BottomNavigationBarItem(
|
||||
icon: const ImageIcon(const TestImageProvider(24, 24)),
|
||||
title: const Text('Tab 2'),
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
|
||||
expect(semantics, includesNodeWith(
|
||||
label: 'Tab 1',
|
||||
hint: 'tab, 1 of 2',
|
||||
flags: <SemanticsFlag>[SemanticsFlag.isSelected],
|
||||
textDirection: TextDirection.ltr,
|
||||
));
|
||||
|
||||
expect(semantics, includesNodeWith(
|
||||
label: 'Tab 2',
|
||||
hint: 'tab, 2 of 2',
|
||||
textDirection: TextDirection.ltr,
|
||||
));
|
||||
|
||||
semantics.dispose();
|
||||
});
|
||||
}
|
||||
|
@ -384,6 +384,7 @@ class SemanticsTester {
|
||||
Iterable<SemanticsNode> nodesWith({
|
||||
String label,
|
||||
String value,
|
||||
String hint,
|
||||
TextDirection textDirection,
|
||||
List<SemanticsAction> actions,
|
||||
List<SemanticsFlag> flags,
|
||||
@ -397,6 +398,8 @@ class SemanticsTester {
|
||||
return false;
|
||||
if (value != null && node.value != value)
|
||||
return false;
|
||||
if (hint != null && node.hint != hint)
|
||||
return false;
|
||||
if (textDirection != null && node.textDirection != textDirection)
|
||||
return false;
|
||||
if (actions != null) {
|
||||
@ -636,6 +639,7 @@ class _IncludesNodeWith extends Matcher {
|
||||
const _IncludesNodeWith({
|
||||
this.label,
|
||||
this.value,
|
||||
this.hint,
|
||||
this.textDirection,
|
||||
this.actions,
|
||||
this.flags,
|
||||
@ -646,6 +650,7 @@ class _IncludesNodeWith extends Matcher {
|
||||
|
||||
final String label;
|
||||
final String value;
|
||||
final String hint;
|
||||
final TextDirection textDirection;
|
||||
final List<SemanticsAction> actions;
|
||||
final List<SemanticsFlag> flags;
|
||||
@ -658,6 +663,7 @@ class _IncludesNodeWith extends Matcher {
|
||||
return item.nodesWith(
|
||||
label: label,
|
||||
value: value,
|
||||
hint: hint,
|
||||
textDirection: textDirection,
|
||||
actions: actions,
|
||||
flags: flags,
|
||||
@ -683,6 +689,8 @@ class _IncludesNodeWith extends Matcher {
|
||||
strings.add('label "$label"');
|
||||
if (value != null)
|
||||
strings.add('value "$value"');
|
||||
if (hint != null)
|
||||
strings.add('hint "$hint"');
|
||||
if (textDirection != null)
|
||||
strings.add(' (${describeEnum(textDirection)})');
|
||||
if (actions != null)
|
||||
@ -706,6 +714,7 @@ class _IncludesNodeWith extends Matcher {
|
||||
Matcher includesNodeWith({
|
||||
String label,
|
||||
String value,
|
||||
String hint,
|
||||
TextDirection textDirection,
|
||||
List<SemanticsAction> actions,
|
||||
List<SemanticsFlag> flags,
|
||||
@ -716,6 +725,7 @@ Matcher includesNodeWith({
|
||||
return new _IncludesNodeWith(
|
||||
label: label,
|
||||
value: value,
|
||||
hint: hint,
|
||||
textDirection: textDirection,
|
||||
actions: actions,
|
||||
flags: flags,
|
||||
|
Loading…
x
Reference in New Issue
Block a user