Unverified Commit ef82f97f authored by chunhtai's avatar chunhtai Committed by GitHub

Adds selected semantics flag to radio button for Apple devices (#125499)

fixes https://github.com/flutter/flutter/issues/125495

The iOS will announce 'Selected, \<label\>, button' for selected radio button after this change
parent 9bf2cd3c
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// 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/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'colors.dart'; import 'colors.dart';
...@@ -232,9 +233,24 @@ class _CupertinoRadioState<T> extends State<CupertinoRadio<T>> with TickerProvid ...@@ -232,9 +233,24 @@ class _CupertinoRadioState<T> extends State<CupertinoRadio<T>> with TickerProvid
final Color effectiveFillColor = widget.fillColor ?? CupertinoColors.white; final Color effectiveFillColor = widget.fillColor ?? CupertinoColors.white;
final bool? accessibilitySelected;
// Apple devices also use `selected` to annotate radio button's semantics
// state.
switch(defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
accessibilitySelected = null;
case TargetPlatform.iOS:
case TargetPlatform.macOS:
accessibilitySelected = widget._selected;
}
return Semantics( return Semantics(
inMutuallyExclusiveGroup: true, inMutuallyExclusiveGroup: true,
checked: widget._selected, checked: widget._selected,
selected: accessibilitySelected,
child: buildToggleable( child: buildToggleable(
focusNode: widget.focusNode, focusNode: widget.focusNode,
autofocus: widget.autofocus, autofocus: widget.autofocus,
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'color_scheme.dart'; import 'color_scheme.dart';
import 'colors.dart'; import 'colors.dart';
...@@ -498,10 +499,24 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg ...@@ -498,10 +499,24 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
? effectiveActivePressedOverlayColor ? effectiveActivePressedOverlayColor
: effectiveInactivePressedOverlayColor; : effectiveInactivePressedOverlayColor;
} }
final bool? accessibilitySelected;
// Apple devices also use `selected` to annotate radio button's semantics
// state.
switch(defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
accessibilitySelected = null;
case TargetPlatform.iOS:
case TargetPlatform.macOS:
accessibilitySelected = widget._selected;
}
return Semantics( return Semantics(
inMutuallyExclusiveGroup: true, inMutuallyExclusiveGroup: true,
checked: widget._selected, checked: widget._selected,
selected: accessibilitySelected,
child: buildToggleable( child: buildToggleable(
focusNode: widget.focusNode, focusNode: widget.focusNode,
autofocus: widget.autofocus, autofocus: widget.autofocus,
......
...@@ -118,6 +118,41 @@ void main() { ...@@ -118,6 +118,41 @@ void main() {
expect(log, equals(<int>[1])); expect(log, equals(<int>[1]));
}); });
testWidgets('Radio selected semantics - platform adaptive', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(CupertinoApp(
home: Center(
child: CupertinoRadio<int>(
value: 1,
groupValue: 1,
onChanged: (int? i) { },
),
),
));
final bool isApple = defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS;
expect(
semantics,
includesNodeWith(
flags: <SemanticsFlag>[
SemanticsFlag.isInMutuallyExclusiveGroup,
SemanticsFlag.hasCheckedState,
SemanticsFlag.hasEnabledState,
SemanticsFlag.isEnabled,
SemanticsFlag.isFocusable,
SemanticsFlag.isChecked,
if (isApple) SemanticsFlag.isSelected,
],
actions: <SemanticsAction>[
SemanticsAction.tap,
],
),
);
semantics.dispose();
}, variant: TargetPlatformVariant.all());
testWidgets('Radio semantics', (WidgetTester tester) async { testWidgets('Radio semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
......
...@@ -194,6 +194,40 @@ void main() { ...@@ -194,6 +194,40 @@ void main() {
expect(tester.getSize(find.byKey(key2)), const Size(40.0, 40.0)); expect(tester.getSize(find.byKey(key2)), const Size(40.0, 40.0));
}); });
testWidgets('Radio selected semantics - platform adaptive', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(Theme(
data: theme,
child: Material(
child: Radio<int>(
value: 1,
groupValue: 1,
onChanged: (int? i) {},
),
),
));
final bool isApple = defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS;
expect(
semantics,
includesNodeWith(
flags: <SemanticsFlag>[
SemanticsFlag.isInMutuallyExclusiveGroup,
SemanticsFlag.hasCheckedState,
SemanticsFlag.hasEnabledState,
SemanticsFlag.isEnabled,
SemanticsFlag.isFocusable,
SemanticsFlag.isChecked,
if (isApple) SemanticsFlag.isSelected,
],
actions: <SemanticsAction>[
SemanticsAction.tap,
],
),
);
semantics.dispose();
}, variant: TargetPlatformVariant.all());
testWidgets('Radio semantics', (WidgetTester tester) async { testWidgets('Radio semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
......
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