@@ -1329,6 +1329,35 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
13291329 return Size .zero;
13301330 }
13311331
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+
13321361 @override
13331362 void performLayout () {
13341363 final BoxConstraints constraints = this .constraints;
@@ -1716,12 +1745,16 @@ class _AffixText extends StatelessWidget {
17161745 this .text,
17171746 this .style,
17181747 this .child,
1748+ this .semanticsSortKey,
1749+ required this .semanticsTag,
17191750 });
17201751
17211752 final bool labelIsFloating;
17221753 final String ? text;
17231754 final TextStyle ? style;
17241755 final Widget ? child;
1756+ final SemanticsSortKey ? semanticsSortKey;
1757+ final SemanticsTag semanticsTag;
17251758
17261759 @override
17271760 Widget build (BuildContext context) {
@@ -1731,7 +1764,11 @@ class _AffixText extends StatelessWidget {
17311764 duration: _kTransitionDuration,
17321765 curve: _kTransitionCurve,
17331766 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+ ),
17351772 ),
17361773 );
17371774 }
@@ -1903,6 +1940,11 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
19031940 late final Animation <double > _floatingLabelAnimation;
19041941 late final AnimationController _shakingLabelController;
19051942 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' );
19061948
19071949 @override
19081950 void initState () {
@@ -2227,22 +2269,42 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
22272269 ),
22282270 );
22292271
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,
22442306 );
2245-
2307+ }
22462308
22472309 final bool decorationIsDense = decoration.isDense ?? false ;
22482310 final double iconSize = decorationIsDense ? 18.0 : 24.0 ;
@@ -2281,7 +2343,9 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
22812343 color: _getPrefixIconColor (themeData, defaults),
22822344 size: iconSize,
22832345 ),
2284- child: decoration.prefixIcon! ,
2346+ child: Semantics (
2347+ child: decoration.prefixIcon,
2348+ ),
22852349 ),
22862350 ),
22872351 ),
@@ -2306,7 +2370,9 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
23062370 color: _getSuffixIconColor (themeData, defaults),
23072371 size: iconSize,
23082372 ),
2309- child: decoration.suffixIcon! ,
2373+ child: Semantics (
2374+ child: decoration.suffixIcon,
2375+ ),
23102376 ),
23112377 ),
23122378 ),
@@ -2383,7 +2449,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
23832449 isDense: decoration.isDense,
23842450 visualDensity: themeData.visualDensity,
23852451 icon: icon,
2386- input: widget.child ,
2452+ input: input ,
23872453 label: label,
23882454 hint: hint,
23892455 prefix: prefix,
0 commit comments