Unverified Commit cb03ca1d authored by xster's avatar xster Committed by GitHub

Semantics for CupertinoTabBar (#19924)

parent 5b30b393
......@@ -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,
......
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