@@ -1329,6 +1329,35 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
1329
1329
return Size .zero;
1330
1330
}
1331
1331
1332
+ ChildSemanticsConfigurationsResult _childSemanticsConfigurationDelegate (List <SemanticsConfiguration > childConfigs) {
1333
+ final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder ();
1334
+ List <SemanticsConfiguration >? prefixMergeGroup;
1335
+ List <SemanticsConfiguration >? suffixMergeGroup;
1336
+ for (final SemanticsConfiguration childConfig in childConfigs) {
1337
+ if (childConfig.tagsChildrenWith (_InputDecoratorState ._kPrefixSemanticsTag)) {
1338
+ prefixMergeGroup ?? = < SemanticsConfiguration > [];
1339
+ prefixMergeGroup.add (childConfig);
1340
+ } else if (childConfig.tagsChildrenWith (_InputDecoratorState ._kSuffixSemanticsTag)) {
1341
+ suffixMergeGroup ?? = < SemanticsConfiguration > [];
1342
+ suffixMergeGroup.add (childConfig);
1343
+ } else {
1344
+ builder.markAsMergeUp (childConfig);
1345
+ }
1346
+ }
1347
+ if (prefixMergeGroup != null ) {
1348
+ builder.markAsSiblingMergeGroup (prefixMergeGroup);
1349
+ }
1350
+ if (suffixMergeGroup != null ) {
1351
+ builder.markAsSiblingMergeGroup (suffixMergeGroup);
1352
+ }
1353
+ return builder.build ();
1354
+ }
1355
+
1356
+ @override
1357
+ void describeSemanticsConfiguration (SemanticsConfiguration config) {
1358
+ config.childConfigurationsDelegate = _childSemanticsConfigurationDelegate;
1359
+ }
1360
+
1332
1361
@override
1333
1362
void performLayout () {
1334
1363
final BoxConstraints constraints = this .constraints;
@@ -1716,12 +1745,16 @@ class _AffixText extends StatelessWidget {
1716
1745
this .text,
1717
1746
this .style,
1718
1747
this .child,
1748
+ this .semanticsSortKey,
1749
+ required this .semanticsTag,
1719
1750
});
1720
1751
1721
1752
final bool labelIsFloating;
1722
1753
final String ? text;
1723
1754
final TextStyle ? style;
1724
1755
final Widget ? child;
1756
+ final SemanticsSortKey ? semanticsSortKey;
1757
+ final SemanticsTag semanticsTag;
1725
1758
1726
1759
@override
1727
1760
Widget build (BuildContext context) {
@@ -1731,7 +1764,11 @@ class _AffixText extends StatelessWidget {
1731
1764
duration: _kTransitionDuration,
1732
1765
curve: _kTransitionCurve,
1733
1766
opacity: labelIsFloating ? 1.0 : 0.0 ,
1734
- child: child ?? (text == null ? null : Text (text! , style: style)),
1767
+ child: Semantics (
1768
+ sortKey: semanticsSortKey,
1769
+ tagForChildren: semanticsTag,
1770
+ child: child ?? (text == null ? null : Text (text! , style: style)),
1771
+ ),
1735
1772
),
1736
1773
);
1737
1774
}
@@ -1903,6 +1940,11 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
1903
1940
late final Animation <double > _floatingLabelAnimation;
1904
1941
late final AnimationController _shakingLabelController;
1905
1942
final _InputBorderGap _borderGap = _InputBorderGap ();
1943
+ static const OrdinalSortKey _kPrefixSemanticsSortOrder = OrdinalSortKey (0 );
1944
+ static const OrdinalSortKey _kInputSemanticsSortOrder = OrdinalSortKey (1 );
1945
+ static const OrdinalSortKey _kSuffixSemanticsSortOrder = OrdinalSortKey (2 );
1946
+ static const SemanticsTag _kPrefixSemanticsTag = SemanticsTag ('_InputDecoratorState.prefix' );
1947
+ static const SemanticsTag _kSuffixSemanticsTag = SemanticsTag ('_InputDecoratorState.suffix' );
1906
1948
1907
1949
@override
1908
1950
void initState () {
@@ -2227,22 +2269,42 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
2227
2269
),
2228
2270
);
2229
2271
2230
- final Widget ? prefix = decoration.prefix == null && decoration.prefixText == null ? null :
2231
- _AffixText (
2232
- labelIsFloating: widget._labelShouldWithdraw,
2233
- text: decoration.prefixText,
2234
- style: MaterialStateProperty .resolveAs (decoration.prefixStyle, materialState) ?? hintStyle,
2235
- child: decoration.prefix,
2236
- );
2237
-
2238
- final Widget ? suffix = decoration.suffix == null && decoration.suffixText == null ? null :
2239
- _AffixText (
2240
- labelIsFloating: widget._labelShouldWithdraw,
2241
- text: decoration.suffixText,
2242
- style: MaterialStateProperty .resolveAs (decoration.suffixStyle, materialState) ?? hintStyle,
2243
- child: decoration.suffix,
2272
+ final bool hasPrefix = decoration.prefix != null || decoration.prefixText != null ;
2273
+ final bool hasSuffix = decoration.suffix != null || decoration.suffixText != null ;
2274
+
2275
+ Widget ? input = widget.child;
2276
+ // If at least two out of the three are visible, it needs semantics sort
2277
+ // order.
2278
+ final bool needsSemanticsSortOrder = widget._labelShouldWithdraw && (input != null ? (hasPrefix || hasSuffix) : (hasPrefix && hasSuffix));
2279
+
2280
+ final Widget ? prefix = hasPrefix
2281
+ ? _AffixText (
2282
+ labelIsFloating: widget._labelShouldWithdraw,
2283
+ text: decoration.prefixText,
2284
+ style: MaterialStateProperty .resolveAs (decoration.prefixStyle, materialState) ?? hintStyle,
2285
+ semanticsSortKey: needsSemanticsSortOrder ? _kPrefixSemanticsSortOrder : null ,
2286
+ semanticsTag: _kPrefixSemanticsTag,
2287
+ child: decoration.prefix,
2288
+ )
2289
+ : null ;
2290
+
2291
+ final Widget ? suffix = hasSuffix
2292
+ ? _AffixText (
2293
+ labelIsFloating: widget._labelShouldWithdraw,
2294
+ text: decoration.suffixText,
2295
+ style: MaterialStateProperty .resolveAs (decoration.suffixStyle, materialState) ?? hintStyle,
2296
+ semanticsSortKey: needsSemanticsSortOrder ? _kSuffixSemanticsSortOrder : null ,
2297
+ semanticsTag: _kSuffixSemanticsTag,
2298
+ child: decoration.suffix,
2299
+ )
2300
+ : null ;
2301
+
2302
+ if (input != null && needsSemanticsSortOrder) {
2303
+ input = Semantics (
2304
+ sortKey: _kInputSemanticsSortOrder,
2305
+ child: input,
2244
2306
);
2245
-
2307
+ }
2246
2308
2247
2309
final bool decorationIsDense = decoration.isDense ?? false ;
2248
2310
final double iconSize = decorationIsDense ? 18.0 : 24.0 ;
@@ -2281,7 +2343,9 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
2281
2343
color: _getPrefixIconColor (themeData, defaults),
2282
2344
size: iconSize,
2283
2345
),
2284
- child: decoration.prefixIcon! ,
2346
+ child: Semantics (
2347
+ child: decoration.prefixIcon,
2348
+ ),
2285
2349
),
2286
2350
),
2287
2351
),
@@ -2306,7 +2370,9 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
2306
2370
color: _getSuffixIconColor (themeData, defaults),
2307
2371
size: iconSize,
2308
2372
),
2309
- child: decoration.suffixIcon! ,
2373
+ child: Semantics (
2374
+ child: decoration.suffixIcon,
2375
+ ),
2310
2376
),
2311
2377
),
2312
2378
),
@@ -2383,7 +2449,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
2383
2449
isDense: decoration.isDense,
2384
2450
visualDensity: themeData.visualDensity,
2385
2451
icon: icon,
2386
- input: widget.child ,
2452
+ input: input ,
2387
2453
label: label,
2388
2454
hint: hint,
2389
2455
prefix: prefix,
0 commit comments