Skip to content

Commit 352ad3a

Browse files
authored
Adds API in semanticsconfiguration to decide how to merge child semanticsConfigurations (#110730)
* Adds semantics merger API and fix input decorator * addressing comments * abstractnode to object * feature complete * addressing comments * fix comments * conditionally add sort order * fix bool * fix test * more fix * fix tests
1 parent 182f9f6 commit 352ad3a

File tree

6 files changed

+833
-67
lines changed

6 files changed

+833
-67
lines changed

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

+85-19
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,35 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin
13261326
return Size.zero;
13271327
}
13281328

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+
13291358
@override
13301359
void performLayout() {
13311360
final BoxConstraints constraints = this.constraints;
@@ -1713,12 +1742,16 @@ class _AffixText extends StatelessWidget {
17131742
this.text,
17141743
this.style,
17151744
this.child,
1745+
this.semanticsSortKey,
1746+
required this.semanticsTag,
17161747
});
17171748

17181749
final bool labelIsFloating;
17191750
final String? text;
17201751
final TextStyle? style;
17211752
final Widget? child;
1753+
final SemanticsSortKey? semanticsSortKey;
1754+
final SemanticsTag semanticsTag;
17221755

17231756
@override
17241757
Widget build(BuildContext context) {
@@ -1728,7 +1761,11 @@ class _AffixText extends StatelessWidget {
17281761
duration: _kTransitionDuration,
17291762
curve: _kTransitionCurve,
17301763
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+
),
17321769
),
17331770
);
17341771
}
@@ -1899,6 +1936,11 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
18991936
late AnimationController _floatingLabelController;
19001937
late AnimationController _shakingLabelController;
19011938
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');
19021944

19031945
@override
19041946
void initState() {
@@ -2218,22 +2260,42 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
22182260
),
22192261
);
22202262

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,
22352297
);
2236-
2298+
}
22372299

22382300
final bool decorationIsDense = decoration.isDense ?? false;
22392301
final double iconSize = decorationIsDense ? 18.0 : 24.0;
@@ -2272,7 +2334,9 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
22722334
color: _getPrefixIconColor(themeData, defaults),
22732335
size: iconSize,
22742336
),
2275-
child: decoration.prefixIcon!,
2337+
child: Semantics(
2338+
child: decoration.prefixIcon,
2339+
),
22762340
),
22772341
),
22782342
),
@@ -2297,7 +2361,9 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
22972361
color: _getSuffixIconColor(themeData, defaults),
22982362
size: iconSize,
22992363
),
2300-
child: decoration.suffixIcon!,
2364+
child: Semantics(
2365+
child: decoration.suffixIcon,
2366+
),
23012367
),
23022368
),
23032369
),
@@ -2374,7 +2440,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
23742440
isDense: decoration.isDense,
23752441
visualDensity: themeData.visualDensity,
23762442
icon: icon,
2377-
input: widget.child,
2443+
input: input,
23782444
label: label,
23792445
hint: hint,
23802446
prefix: prefix,

0 commit comments

Comments
 (0)