Fixes semantics ordering when there are multiple TextFields with pref… (#148267)

…ix and suffix

fixes https://github.com/flutter/flutter/issues/148248
This commit is contained in:
chunhtai 2024-05-14 15:22:51 -07:00 committed by GitHub
parent 2d3e55da28
commit de9ca5c1c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 58 additions and 6 deletions

View file

@ -1865,9 +1865,11 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
late final CurvedAnimation _floatingLabelAnimation;
late final AnimationController _shakingLabelController;
final _InputBorderGap _borderGap = _InputBorderGap();
static const OrdinalSortKey _kPrefixSemanticsSortOrder = OrdinalSortKey(0);
static const OrdinalSortKey _kInputSemanticsSortOrder = OrdinalSortKey(1);
static const OrdinalSortKey _kSuffixSemanticsSortOrder = OrdinalSortKey(2);
// Provide a unique name to avoid mixing up sort order with sibling input
// decorators.
late final OrdinalSortKey _prefixSemanticsSortOrder = OrdinalSortKey(0, name: hashCode.toString());
late final OrdinalSortKey _inputSemanticsSortOrder = OrdinalSortKey(1, name: hashCode.toString());
late final OrdinalSortKey _suffixSemanticsSortOrder = OrdinalSortKey(2, name: hashCode.toString());
static const SemanticsTag _kPrefixSemanticsTag = SemanticsTag('_InputDecoratorState.prefix');
static const SemanticsTag _kSuffixSemanticsTag = SemanticsTag('_InputDecoratorState.suffix');
@ -2219,7 +2221,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
labelIsFloating: widget._labelShouldWithdraw,
text: decoration.prefixText,
style: MaterialStateProperty.resolveAs(decoration.prefixStyle, materialState) ?? hintStyle,
semanticsSortKey: needsSemanticsSortOrder ? _kPrefixSemanticsSortOrder : null,
semanticsSortKey: needsSemanticsSortOrder ? _prefixSemanticsSortOrder : null,
semanticsTag: _kPrefixSemanticsTag,
child: decoration.prefix,
)
@ -2230,7 +2232,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
labelIsFloating: widget._labelShouldWithdraw,
text: decoration.suffixText,
style: MaterialStateProperty.resolveAs(decoration.suffixStyle, materialState) ?? hintStyle,
semanticsSortKey: needsSemanticsSortOrder ? _kSuffixSemanticsSortOrder : null,
semanticsSortKey: needsSemanticsSortOrder ? _suffixSemanticsSortOrder : null,
semanticsTag: _kSuffixSemanticsTag,
child: decoration.suffix,
)
@ -2238,7 +2240,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
if (input != null && needsSemanticsSortOrder) {
input = Semantics(
sortKey: _kInputSemanticsSortOrder,
sortKey: _inputSemanticsSortOrder,
child: input,
);
}

View file

@ -1831,6 +1831,56 @@ void main() {
expect(handle.opacity.value, equals(0.0));
});
testWidgets('multiple text fields with prefix and suffix have correct semantics order.', (WidgetTester tester) async {
final TextEditingController controller1 = _textEditingController(
text: 'abc',
);
final TextEditingController controller2 = _textEditingController(
text: 'def',
);
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Column(
children: <Widget>[
TextField(
decoration: const InputDecoration(
prefixText: 'prefix1',
suffixText: 'suffix1',
),
enabled: false,
controller: controller1,
),
TextField(
decoration: const InputDecoration(
prefixText: 'prefix2',
suffixText: 'suffix2',
),
enabled: false,
controller: controller2,
),
],
),
),
),
);
final List<String> orders = tester.semantics.simulatedAccessibilityTraversal(
startNode: find.semantics.byLabel('prefix1'),
).map((SemanticsNode node) => node.label + node.value).toList();
expect(
orders,
<String>[
'prefix1',
'abc',
'suffix1',
'prefix2',
'def',
'suffix2',
],
);
});
testWidgets('selection handles are excluded from the semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
final TextEditingController controller = _textEditingController();