Commit 5e595d12 authored by amirh's avatar amirh Committed by GitHub

Allow specifying and a11y label for Icon widget (#12475)

* Allow specifying and a11y label for Icon widget
parent c38b8434
...@@ -35,7 +35,8 @@ class Icon extends StatelessWidget { ...@@ -35,7 +35,8 @@ class Icon extends StatelessWidget {
const Icon(this.icon, { const Icon(this.icon, {
Key key, Key key,
this.size, this.size,
this.color this.color,
this.semanticLabel,
}) : super(key: key); }) : super(key: key);
/// The icon to display. The available icons are described in [Icons]. /// The icon to display. The available icons are described in [Icons].
...@@ -83,6 +84,14 @@ class Icon extends StatelessWidget { ...@@ -83,6 +84,14 @@ class Icon extends StatelessWidget {
/// ``` /// ```
final Color color; final Color color;
/// Semantic label for the icon.
///
/// This would be read out in accessibility modes (e.g TalkBack/VoiceOver).
/// This label does not show in the UI.
///
/// See [Semantics.label];
final String semanticLabel;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasDirectionality(context)); assert(debugCheckHasDirectionality(context));
...@@ -93,14 +102,15 @@ class Icon extends StatelessWidget { ...@@ -93,14 +102,15 @@ class Icon extends StatelessWidget {
final double iconSize = size ?? iconTheme.size; final double iconSize = size ?? iconTheme.size;
if (icon == null) if (icon == null)
return new SizedBox(width: iconSize, height: iconSize); return _wrapWithSemantics(new SizedBox(width: iconSize, height: iconSize));
final double iconOpacity = iconTheme.opacity; final double iconOpacity = iconTheme.opacity;
Color iconColor = color ?? iconTheme.color; Color iconColor = color ?? iconTheme.color;
if (iconOpacity != 1.0) if (iconOpacity != 1.0)
iconColor = iconColor.withOpacity(iconColor.opacity * iconOpacity); iconColor = iconColor.withOpacity(iconColor.opacity * iconOpacity);
return new ExcludeSemantics( return _wrapWithSemantics(
new ExcludeSemantics(
child: new SizedBox( child: new SizedBox(
width: iconSize, width: iconSize,
height: iconSize, height: iconSize,
...@@ -119,6 +129,18 @@ class Icon extends StatelessWidget { ...@@ -119,6 +129,18 @@ class Icon extends StatelessWidget {
), ),
), ),
), ),
),
);
}
/// Wraps the widget with a Semantics widget if [semanticLabel] is set.
Widget _wrapWithSemantics(Widget widget) {
if (semanticLabel == null)
return widget;
return new Semantics(
child: widget,
label: semanticLabel,
); );
} }
......
...@@ -2,9 +2,12 @@ ...@@ -2,9 +2,12 @@
// 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 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'semantics_tester.dart';
void main() { void main() {
testWidgets('Can set opacity for an Icon', (WidgetTester tester) async { testWidgets('Can set opacity for an Icon', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
...@@ -122,4 +125,40 @@ void main() { ...@@ -122,4 +125,40 @@ void main() {
final RichText richText = tester.firstWidget(find.byType(RichText)); final RichText richText = tester.firstWidget(find.byType(RichText));
expect(richText.text.style.fontFamily, equals('Roboto')); expect(richText.text.style.fontFamily, equals('Roboto'));
}); });
testWidgets('Icon with semantic label', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: const Center(
child: const Icon(
Icons.title,
semanticLabel: 'a label',
),
),
),
);
expect(semantics, hasSemantics(new TestSemantics.root(label: 'a label')));
});
testWidgets('Null icon with semantic label', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: const Center(
child: const Icon(
null,
semanticLabel: 'a label',
),
),
),
);
expect(semantics, hasSemantics(new TestSemantics.root(label: 'a label')));
});
} }
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