@@ -1326,6 +1326,35 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
1326
1326
return Size .zero;
1327
1327
}
1328
1328
1329
+ ChildSemanticsConfigurationsResult _childSemanticsConfigurationDelegate (List <SemanticsConfiguration > childConfigs) {
1330
+ final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder ();
1331
+ List <SemanticsConfiguration >? prefixMergeGroup;
1332
+ List <SemanticsConfiguration >? suffixMergeGroup;
1333
+ for (final SemanticsConfiguration childConfig in childConfigs) {
1334
+ if (childConfig.tagsChildrenWith (_InputDecoratorState ._kPrefixSemanticsTag)) {
1335
+ prefixMergeGroup ?? = < SemanticsConfiguration > [];
1336
+ prefixMergeGroup.add (childConfig);
1337
+ } else if (childConfig.tagsChildrenWith (_InputDecoratorState ._kSuffixSemanticsTag)) {
1338
+ suffixMergeGroup ?? = < SemanticsConfiguration > [];
1339
+ suffixMergeGroup.add (childConfig);
1340
+ } else {
1341
+ builder.markAsMergeUp (childConfig);
1342
+ }
1343
+ }
1344
+ if (prefixMergeGroup != null ) {
1345
+ builder.markAsSiblingMergeGroup (prefixMergeGroup);
1346
+ }
1347
+ if (suffixMergeGroup != null ) {
1348
+ builder.markAsSiblingMergeGroup (suffixMergeGroup);
1349
+ }
1350
+ return builder.build ();
1351
+ }
1352
+
1353
+ @override
1354
+ void describeSemanticsConfiguration (SemanticsConfiguration config) {
1355
+ config.childConfigurationsDelegate = _childSemanticsConfigurationDelegate;
1356
+ }
1357
+
1329
1358
@override
1330
1359
void performLayout () {
1331
1360
final BoxConstraints constraints = this .constraints;
@@ -1713,12 +1742,16 @@ class _AffixText extends StatelessWidget {
1713
1742
this .text,
1714
1743
this .style,
1715
1744
this .child,
1745
+ this .semanticsSortKey,
1746
+ required this .semanticsTag,
1716
1747
});
1717
1748
1718
1749
final bool labelIsFloating;
1719
1750
final String ? text;
1720
1751
final TextStyle ? style;
1721
1752
final Widget ? child;
1753
+ final SemanticsSortKey ? semanticsSortKey;
1754
+ final SemanticsTag semanticsTag;
1722
1755
1723
1756
@override
1724
1757
Widget build (BuildContext context) {
@@ -1728,7 +1761,11 @@ class _AffixText extends StatelessWidget {
1728
1761
duration: _kTransitionDuration,
1729
1762
curve: _kTransitionCurve,
1730
1763
opacity: labelIsFloating ? 1.0 : 0.0 ,
1731
- child: child ?? (text == null ? null : Text (text! , style: style)),
1764
+ child: Semantics (
1765
+ sortKey: semanticsSortKey,
1766
+ tagForChildren: semanticsTag,
1767
+ child: child ?? (text == null ? null : Text (text! , style: style)),
1768
+ ),
1732
1769
),
1733
1770
);
1734
1771
}
@@ -1899,6 +1936,11 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
1899
1936
late AnimationController _floatingLabelController;
1900
1937
late AnimationController _shakingLabelController;
1901
1938
final _InputBorderGap _borderGap = _InputBorderGap ();
1939
+ static const OrdinalSortKey _kPrefixSemanticsSortOrder = OrdinalSortKey (0 );
1940
+ static const OrdinalSortKey _kInputSemanticsSortOrder = OrdinalSortKey (1 );
1941
+ static const OrdinalSortKey _kSuffixSemanticsSortOrder = OrdinalSortKey (2 );
1942
+ static const SemanticsTag _kPrefixSemanticsTag = SemanticsTag ('_InputDecoratorState.prefix' );
1943
+ static const SemanticsTag _kSuffixSemanticsTag = SemanticsTag ('_InputDecoratorState.suffix' );
1902
1944
1903
1945
@override
1904
1946
void initState () {
@@ -2218,22 +2260,42 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
2218
2260
),
2219
2261
);
2220
2262
2221
- final Widget ? prefix = decoration.prefix == null && decoration.prefixText == null ? null :
2222
- _AffixText (
2223
- labelIsFloating: widget._labelShouldWithdraw,
2224
- text: decoration.prefixText,
2225
- style: MaterialStateProperty .resolveAs (decoration.prefixStyle, materialState) ?? hintStyle,
2226
- child: decoration.prefix,
2227
- );
2228
-
2229
- final Widget ? suffix = decoration.suffix == null && decoration.suffixText == null ? null :
2230
- _AffixText (
2231
- labelIsFloating: widget._labelShouldWithdraw,
2232
- text: decoration.suffixText,
2233
- style: MaterialStateProperty .resolveAs (decoration.suffixStyle, materialState) ?? hintStyle,
2234
- child: decoration.suffix,
2263
+ final bool hasPrefix = decoration.prefix != null || decoration.prefixText != null ;
2264
+ final bool hasSuffix = decoration.suffix != null || decoration.suffixText != null ;
2265
+
2266
+ Widget ? input = widget.child;
2267
+ // If at least two out of the three are visible, it needs semantics sort
2268
+ // order.
2269
+ final bool needsSemanticsSortOrder = widget._labelShouldWithdraw && (input != null ? (hasPrefix || hasSuffix) : (hasPrefix && hasSuffix));
2270
+
2271
+ final Widget ? prefix = hasPrefix
2272
+ ? _AffixText (
2273
+ labelIsFloating: widget._labelShouldWithdraw,
2274
+ text: decoration.prefixText,
2275
+ style: MaterialStateProperty .resolveAs (decoration.prefixStyle, materialState) ?? hintStyle,
2276
+ semanticsSortKey: needsSemanticsSortOrder ? _kPrefixSemanticsSortOrder : null ,
2277
+ semanticsTag: _kPrefixSemanticsTag,
2278
+ child: decoration.prefix,
2279
+ )
2280
+ : null ;
2281
+
2282
+ final Widget ? suffix = hasSuffix
2283
+ ? _AffixText (
2284
+ labelIsFloating: widget._labelShouldWithdraw,
2285
+ text: decoration.suffixText,
2286
+ style: MaterialStateProperty .resolveAs (decoration.suffixStyle, materialState) ?? hintStyle,
2287
+ semanticsSortKey: needsSemanticsSortOrder ? _kSuffixSemanticsSortOrder : null ,
2288
+ semanticsTag: _kSuffixSemanticsTag,
2289
+ child: decoration.suffix,
2290
+ )
2291
+ : null ;
2292
+
2293
+ if (input != null && needsSemanticsSortOrder) {
2294
+ input = Semantics (
2295
+ sortKey: _kInputSemanticsSortOrder,
2296
+ child: input,
2235
2297
);
2236
-
2298
+ }
2237
2299
2238
2300
final bool decorationIsDense = decoration.isDense ?? false ;
2239
2301
final double iconSize = decorationIsDense ? 18.0 : 24.0 ;
@@ -2272,7 +2334,9 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
2272
2334
color: _getPrefixIconColor (themeData, defaults),
2273
2335
size: iconSize,
2274
2336
),
2275
- child: decoration.prefixIcon! ,
2337
+ child: Semantics (
2338
+ child: decoration.prefixIcon,
2339
+ ),
2276
2340
),
2277
2341
),
2278
2342
),
@@ -2297,7 +2361,9 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
2297
2361
color: _getSuffixIconColor (themeData, defaults),
2298
2362
size: iconSize,
2299
2363
),
2300
- child: decoration.suffixIcon! ,
2364
+ child: Semantics (
2365
+ child: decoration.suffixIcon,
2366
+ ),
2301
2367
),
2302
2368
),
2303
2369
),
@@ -2374,7 +2440,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
2374
2440
isDense: decoration.isDense,
2375
2441
visualDensity: themeData.visualDensity,
2376
2442
icon: icon,
2377
- input: widget.child ,
2443
+ input: input ,
2378
2444
label: label,
2379
2445
hint: hint,
2380
2446
prefix: prefix,
0 commit comments