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

Semantics for CupertinoTabBar (#19924)

parent 5b30b393
...@@ -156,25 +156,32 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { ...@@ -156,25 +156,32 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget {
final List<Widget> result = <Widget>[]; final List<Widget> result = <Widget>[];
for (int index = 0; index < items.length; index += 1) { for (int index = 0; index < items.length; index += 1) {
final bool active = index == currentIndex;
result.add( result.add(
_wrapActiveItem( _wrapActiveItem(
new Expanded( new Expanded(
child: new GestureDetector( child: new Semantics(
behavior: HitTestBehavior.opaque, selected: active,
onTap: onTap == null ? null : () { onTap(index); }, // TODO(https://github.com/flutter/flutter/issues/13452):
child: new Padding( // This needs localization support.
padding: const EdgeInsets.only(bottom: 4.0), hint: 'tab, ${index + 1} of ${items.length}',
child: new Column( child: new GestureDetector(
mainAxisAlignment: MainAxisAlignment.end, behavior: HitTestBehavior.opaque,
children: <Widget> [ onTap: onTap == null ? null : () { onTap(index); },
new Expanded(child: new Center(child: items[index].icon)), child: new Padding(
items[index].title, padding: const EdgeInsets.only(bottom: 4.0),
], child: new Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget> [
new Expanded(child: new Center(child: items[index].icon)),
items[index].title,
],
),
), ),
), ),
), ),
), ),
active: index == currentIndex, active: active,
), ),
); );
} }
...@@ -183,7 +190,7 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { ...@@ -183,7 +190,7 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget {
} }
/// Change the active tab item's icon and title colors to active. /// 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) if (!active)
return item; return item;
......
...@@ -6,6 +6,7 @@ import 'package:flutter/cupertino.dart'; ...@@ -6,6 +6,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../painting/mocks_for_image_cache.dart'; import '../painting/mocks_for_image_cache.dart';
import '../widgets/semantics_tester.dart';
Future<Null> pumpWidgetWithBoilerplate(WidgetTester tester, Widget widget) async { Future<Null> pumpWidgetWithBoilerplate(WidgetTester tester, Widget widget) async {
await tester.pumpWidget( await tester.pumpWidget(
...@@ -169,4 +170,39 @@ void main() { ...@@ -169,4 +170,39 @@ void main() {
await tester.tap(find.text('Tab 1')); await tester.tap(find.text('Tab 1'));
expect(callbackTab, 0); 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 { ...@@ -384,6 +384,7 @@ class SemanticsTester {
Iterable<SemanticsNode> nodesWith({ Iterable<SemanticsNode> nodesWith({
String label, String label,
String value, String value,
String hint,
TextDirection textDirection, TextDirection textDirection,
List<SemanticsAction> actions, List<SemanticsAction> actions,
List<SemanticsFlag> flags, List<SemanticsFlag> flags,
...@@ -397,6 +398,8 @@ class SemanticsTester { ...@@ -397,6 +398,8 @@ class SemanticsTester {
return false; return false;
if (value != null && node.value != value) if (value != null && node.value != value)
return false; return false;
if (hint != null && node.hint != hint)
return false;
if (textDirection != null && node.textDirection != textDirection) if (textDirection != null && node.textDirection != textDirection)
return false; return false;
if (actions != null) { if (actions != null) {
...@@ -636,6 +639,7 @@ class _IncludesNodeWith extends Matcher { ...@@ -636,6 +639,7 @@ class _IncludesNodeWith extends Matcher {
const _IncludesNodeWith({ const _IncludesNodeWith({
this.label, this.label,
this.value, this.value,
this.hint,
this.textDirection, this.textDirection,
this.actions, this.actions,
this.flags, this.flags,
...@@ -646,6 +650,7 @@ class _IncludesNodeWith extends Matcher { ...@@ -646,6 +650,7 @@ class _IncludesNodeWith extends Matcher {
final String label; final String label;
final String value; final String value;
final String hint;
final TextDirection textDirection; final TextDirection textDirection;
final List<SemanticsAction> actions; final List<SemanticsAction> actions;
final List<SemanticsFlag> flags; final List<SemanticsFlag> flags;
...@@ -658,6 +663,7 @@ class _IncludesNodeWith extends Matcher { ...@@ -658,6 +663,7 @@ class _IncludesNodeWith extends Matcher {
return item.nodesWith( return item.nodesWith(
label: label, label: label,
value: value, value: value,
hint: hint,
textDirection: textDirection, textDirection: textDirection,
actions: actions, actions: actions,
flags: flags, flags: flags,
...@@ -683,6 +689,8 @@ class _IncludesNodeWith extends Matcher { ...@@ -683,6 +689,8 @@ class _IncludesNodeWith extends Matcher {
strings.add('label "$label"'); strings.add('label "$label"');
if (value != null) if (value != null)
strings.add('value "$value"'); strings.add('value "$value"');
if (hint != null)
strings.add('hint "$hint"');
if (textDirection != null) if (textDirection != null)
strings.add(' (${describeEnum(textDirection)})'); strings.add(' (${describeEnum(textDirection)})');
if (actions != null) if (actions != null)
...@@ -706,6 +714,7 @@ class _IncludesNodeWith extends Matcher { ...@@ -706,6 +714,7 @@ class _IncludesNodeWith extends Matcher {
Matcher includesNodeWith({ Matcher includesNodeWith({
String label, String label,
String value, String value,
String hint,
TextDirection textDirection, TextDirection textDirection,
List<SemanticsAction> actions, List<SemanticsAction> actions,
List<SemanticsFlag> flags, List<SemanticsFlag> flags,
...@@ -716,6 +725,7 @@ Matcher includesNodeWith({ ...@@ -716,6 +725,7 @@ Matcher includesNodeWith({
return new _IncludesNodeWith( return new _IncludesNodeWith(
label: label, label: label,
value: value, value: value,
hint: hint,
textDirection: textDirection, textDirection: textDirection,
actions: actions, actions: actions,
flags: flags, 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