Unverified Commit ffdd6e1b authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Toggle whether label or hint contribute to text field semantics when unfocused/focused (#19790)

parent 6dc18525
......@@ -540,12 +540,14 @@ class _RenderDecoration extends RenderBox {
@required _Decoration decoration,
@required TextDirection textDirection,
@required TextBaseline textBaseline,
@required bool isFocused,
}) : assert(decoration != null),
assert(textDirection != null),
assert(textBaseline != null),
_decoration = decoration,
_textDirection = textDirection,
_textBaseline = textBaseline;
_textBaseline = textBaseline,
_isFocused = isFocused;
final Map<_DecorationSlot, RenderBox> slotToChild = <_DecorationSlot, RenderBox>{};
final Map<RenderBox, _DecorationSlot> childToSlot = <RenderBox, _DecorationSlot>{};
......@@ -686,6 +688,16 @@ class _RenderDecoration extends RenderBox {
markNeedsLayout();
}
bool get isFocused => _isFocused;
bool _isFocused;
set isFocused(bool value) {
assert(value != null);
if (_isFocused == value)
return;
_isFocused = value;
markNeedsSemanticsUpdate();
}
@override
void attach(PipelineOwner owner) {
super.attach(owner);
......@@ -710,6 +722,35 @@ class _RenderDecoration extends RenderBox {
_children.forEach(visitor);
}
@override
void visitChildrenForSemantics(RenderObjectVisitor visitor) {
if (icon != null)
visitor(icon);
if (prefix != null)
visitor(prefix);
if (prefixIcon != null)
visitor(prefixIcon);
if (isFocused && hint != null) {
// Bypass opacity to always read hint when focused. This prevents the
// label from changing when text is entered.
final RenderProxyBox typedHint = hint;
visitor(typedHint.child);
} else if (!isFocused && label != null)
visitor(label);
if (input != null)
visitor(input);
if (suffixIcon != null)
visitor(suffixIcon);
if (suffix != null)
visitor(suffix);
if (container != null)
visitor(container);
if (helperError != null)
visitor(helperError);
if (counter != null)
visitor(counter);
}
@override
List<DiagnosticsNode> debugDescribeChildren() {
final List<DiagnosticsNode> value = <DiagnosticsNode>[];
......@@ -1301,6 +1342,7 @@ class _Decorator extends RenderObjectWidget {
@required this.decoration,
@required this.textDirection,
@required this.textBaseline,
@required this.isFocused,
}) : assert(decoration != null),
assert(textDirection != null),
assert(textBaseline != null),
......@@ -1309,6 +1351,7 @@ class _Decorator extends RenderObjectWidget {
final _Decoration decoration;
final TextDirection textDirection;
final TextBaseline textBaseline;
final bool isFocused;
@override
_RenderDecorationElement createElement() => new _RenderDecorationElement(this);
......@@ -1319,6 +1362,7 @@ class _Decorator extends RenderObjectWidget {
decoration: decoration,
textDirection: textDirection,
textBaseline: textBaseline,
isFocused: isFocused,
);
}
......@@ -1327,7 +1371,8 @@ class _Decorator extends RenderObjectWidget {
renderObject
..decoration = decoration
..textDirection = textDirection
..textBaseline = textBaseline;
..textBaseline = textBaseline
..isFocused = isFocused;
}
}
......@@ -1784,6 +1829,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
? const EdgeInsets.fromLTRB(12.0, 20.0, 12.0, 12.0)
: const EdgeInsets.fromLTRB(12.0, 24.0, 12.0, 16.0));
}
return new _Decorator(
decoration: new _Decoration(
contentPadding: contentPadding,
......@@ -1803,9 +1849,10 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
helperError: helperError,
counter: counter,
container: container,
),
textDirection: textDirection,
textBaseline: textBaseline,
),
textDirection: textDirection,
textBaseline: textBaseline,
isFocused: isFocused,
);
}
}
......
......@@ -2250,4 +2250,68 @@ void main() {
expect(focusNode.hasFocus, isFalse);
});
testWidgets('TextField semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
final TextEditingController controller = new TextEditingController();
final Key key = new UniqueKey();
await tester.pumpWidget(
overlay(
child: new TextField(
key: key,
controller: controller,
decoration: const InputDecoration(
labelText: 'label',
hintText: 'hint',
helperText: 'helper',
counterText: 'counter',
),
),
),
);
expect(semantics, hasSemantics(new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
label: 'label\nhelper\ncounter',
id: 1,
textDirection: TextDirection.ltr,
actions: <SemanticsAction>[
SemanticsAction.tap,
],
flags: <SemanticsFlag>[
SemanticsFlag.isTextField,
],
),
],
), ignoreTransform: true, ignoreRect: true));
await tester.tap(find.byType(TextField));
await tester.pump();
expect(semantics, hasSemantics(new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
label: 'hint\nhelper\ncounter',
id: 1,
textDirection: TextDirection.ltr,
textSelection: const TextSelection(baseOffset: 0, extentOffset: 0),
actions: <SemanticsAction>[
SemanticsAction.tap,
SemanticsAction.setSelection,
SemanticsAction.paste,
],
flags: <SemanticsFlag>[
SemanticsFlag.isTextField,
SemanticsFlag.isFocused,
],
),
],
), ignoreTransform: true, ignoreRect: true));
controller.text = 'hello';
await tester.pump();
semantics.dispose();
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment