Skip to content

Commit de9ca5c

Browse files
authored
Fixes semantics ordering when there are multiple TextFields with pref… (#148267)
�ix and suffix fixes flutter/flutter#148248
1 parent 2d3e55d commit de9ca5c

2 files changed

Lines changed: 58 additions & 6 deletions

File tree

packages/flutter/lib/src/material/input_decorator.dart

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,9 +1865,11 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
18651865
late final CurvedAnimation _floatingLabelAnimation;
18661866
late final AnimationController _shakingLabelController;
18671867
final _InputBorderGap _borderGap = _InputBorderGap();
1868-
static const OrdinalSortKey _kPrefixSemanticsSortOrder = OrdinalSortKey(0);
1869-
static const OrdinalSortKey _kInputSemanticsSortOrder = OrdinalSortKey(1);
1870-
static const OrdinalSortKey _kSuffixSemanticsSortOrder = OrdinalSortKey(2);
1868+
// Provide a unique name to avoid mixing up sort order with sibling input
1869+
// decorators.
1870+
late final OrdinalSortKey _prefixSemanticsSortOrder = OrdinalSortKey(0, name: hashCode.toString());
1871+
late final OrdinalSortKey _inputSemanticsSortOrder = OrdinalSortKey(1, name: hashCode.toString());
1872+
late final OrdinalSortKey _suffixSemanticsSortOrder = OrdinalSortKey(2, name: hashCode.toString());
18711873
static const SemanticsTag _kPrefixSemanticsTag = SemanticsTag('_InputDecoratorState.prefix');
18721874
static const SemanticsTag _kSuffixSemanticsTag = SemanticsTag('_InputDecoratorState.suffix');
18731875

@@ -2219,7 +2221,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
22192221
labelIsFloating: widget._labelShouldWithdraw,
22202222
text: decoration.prefixText,
22212223
style: MaterialStateProperty.resolveAs(decoration.prefixStyle, materialState) ?? hintStyle,
2222-
semanticsSortKey: needsSemanticsSortOrder ? _kPrefixSemanticsSortOrder : null,
2224+
semanticsSortKey: needsSemanticsSortOrder ? _prefixSemanticsSortOrder : null,
22232225
semanticsTag: _kPrefixSemanticsTag,
22242226
child: decoration.prefix,
22252227
)
@@ -2230,15 +2232,15 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
22302232
labelIsFloating: widget._labelShouldWithdraw,
22312233
text: decoration.suffixText,
22322234
style: MaterialStateProperty.resolveAs(decoration.suffixStyle, materialState) ?? hintStyle,
2233-
semanticsSortKey: needsSemanticsSortOrder ? _kSuffixSemanticsSortOrder : null,
2235+
semanticsSortKey: needsSemanticsSortOrder ? _suffixSemanticsSortOrder : null,
22342236
semanticsTag: _kSuffixSemanticsTag,
22352237
child: decoration.suffix,
22362238
)
22372239
: null;
22382240

22392241
if (input != null && needsSemanticsSortOrder) {
22402242
input = Semantics(
2241-
sortKey: _kInputSemanticsSortOrder,
2243+
sortKey: _inputSemanticsSortOrder,
22422244
child: input,
22432245
);
22442246
}

packages/flutter/test/material/text_field_test.dart

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,6 +1831,56 @@ void main() {
18311831
expect(handle.opacity.value, equals(0.0));
18321832
});
18331833

1834+
testWidgets('multiple text fields with prefix and suffix have correct semantics order.', (WidgetTester tester) async {
1835+
final TextEditingController controller1 = _textEditingController(
1836+
text: 'abc',
1837+
);
1838+
final TextEditingController controller2 = _textEditingController(
1839+
text: 'def',
1840+
);
1841+
await tester.pumpWidget(
1842+
MaterialApp(
1843+
home: Material(
1844+
child: Column(
1845+
children: <Widget>[
1846+
TextField(
1847+
decoration: const InputDecoration(
1848+
prefixText: 'prefix1',
1849+
suffixText: 'suffix1',
1850+
),
1851+
enabled: false,
1852+
controller: controller1,
1853+
),
1854+
TextField(
1855+
decoration: const InputDecoration(
1856+
prefixText: 'prefix2',
1857+
suffixText: 'suffix2',
1858+
),
1859+
enabled: false,
1860+
controller: controller2,
1861+
),
1862+
],
1863+
),
1864+
),
1865+
),
1866+
);
1867+
final List<String> orders = tester.semantics.simulatedAccessibilityTraversal(
1868+
startNode: find.semantics.byLabel('prefix1'),
1869+
).map((SemanticsNode node) => node.label + node.value).toList();
1870+
1871+
expect(
1872+
orders,
1873+
<String>[
1874+
'prefix1',
1875+
'abc',
1876+
'suffix1',
1877+
'prefix2',
1878+
'def',
1879+
'suffix2',
1880+
],
1881+
);
1882+
});
1883+
18341884
testWidgets('selection handles are excluded from the semantics', (WidgetTester tester) async {
18351885
final SemanticsTester semantics = SemanticsTester(tester);
18361886
final TextEditingController controller = _textEditingController();

0 commit comments

Comments
 (0)