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 { ...@@ -540,12 +540,14 @@ class _RenderDecoration extends RenderBox {
@required _Decoration decoration, @required _Decoration decoration,
@required TextDirection textDirection, @required TextDirection textDirection,
@required TextBaseline textBaseline, @required TextBaseline textBaseline,
@required bool isFocused,
}) : assert(decoration != null), }) : assert(decoration != null),
assert(textDirection != null), assert(textDirection != null),
assert(textBaseline != null), assert(textBaseline != null),
_decoration = decoration, _decoration = decoration,
_textDirection = textDirection, _textDirection = textDirection,
_textBaseline = textBaseline; _textBaseline = textBaseline,
_isFocused = isFocused;
final Map<_DecorationSlot, RenderBox> slotToChild = <_DecorationSlot, RenderBox>{}; final Map<_DecorationSlot, RenderBox> slotToChild = <_DecorationSlot, RenderBox>{};
final Map<RenderBox, _DecorationSlot> childToSlot = <RenderBox, _DecorationSlot>{}; final Map<RenderBox, _DecorationSlot> childToSlot = <RenderBox, _DecorationSlot>{};
...@@ -686,6 +688,16 @@ class _RenderDecoration extends RenderBox { ...@@ -686,6 +688,16 @@ class _RenderDecoration extends RenderBox {
markNeedsLayout(); markNeedsLayout();
} }
bool get isFocused => _isFocused;
bool _isFocused;
set isFocused(bool value) {
assert(value != null);
if (_isFocused == value)
return;
_isFocused = value;
markNeedsSemanticsUpdate();
}
@override @override
void attach(PipelineOwner owner) { void attach(PipelineOwner owner) {
super.attach(owner); super.attach(owner);
...@@ -710,6 +722,35 @@ class _RenderDecoration extends RenderBox { ...@@ -710,6 +722,35 @@ class _RenderDecoration extends RenderBox {
_children.forEach(visitor); _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 @override
List<DiagnosticsNode> debugDescribeChildren() { List<DiagnosticsNode> debugDescribeChildren() {
final List<DiagnosticsNode> value = <DiagnosticsNode>[]; final List<DiagnosticsNode> value = <DiagnosticsNode>[];
...@@ -1301,6 +1342,7 @@ class _Decorator extends RenderObjectWidget { ...@@ -1301,6 +1342,7 @@ class _Decorator extends RenderObjectWidget {
@required this.decoration, @required this.decoration,
@required this.textDirection, @required this.textDirection,
@required this.textBaseline, @required this.textBaseline,
@required this.isFocused,
}) : assert(decoration != null), }) : assert(decoration != null),
assert(textDirection != null), assert(textDirection != null),
assert(textBaseline != null), assert(textBaseline != null),
...@@ -1309,6 +1351,7 @@ class _Decorator extends RenderObjectWidget { ...@@ -1309,6 +1351,7 @@ class _Decorator extends RenderObjectWidget {
final _Decoration decoration; final _Decoration decoration;
final TextDirection textDirection; final TextDirection textDirection;
final TextBaseline textBaseline; final TextBaseline textBaseline;
final bool isFocused;
@override @override
_RenderDecorationElement createElement() => new _RenderDecorationElement(this); _RenderDecorationElement createElement() => new _RenderDecorationElement(this);
...@@ -1319,6 +1362,7 @@ class _Decorator extends RenderObjectWidget { ...@@ -1319,6 +1362,7 @@ class _Decorator extends RenderObjectWidget {
decoration: decoration, decoration: decoration,
textDirection: textDirection, textDirection: textDirection,
textBaseline: textBaseline, textBaseline: textBaseline,
isFocused: isFocused,
); );
} }
...@@ -1327,7 +1371,8 @@ class _Decorator extends RenderObjectWidget { ...@@ -1327,7 +1371,8 @@ class _Decorator extends RenderObjectWidget {
renderObject renderObject
..decoration = decoration ..decoration = decoration
..textDirection = textDirection ..textDirection = textDirection
..textBaseline = textBaseline; ..textBaseline = textBaseline
..isFocused = isFocused;
} }
} }
...@@ -1784,6 +1829,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat ...@@ -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, 20.0, 12.0, 12.0)
: const EdgeInsets.fromLTRB(12.0, 24.0, 12.0, 16.0)); : const EdgeInsets.fromLTRB(12.0, 24.0, 12.0, 16.0));
} }
return new _Decorator( return new _Decorator(
decoration: new _Decoration( decoration: new _Decoration(
contentPadding: contentPadding, contentPadding: contentPadding,
...@@ -1806,6 +1852,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat ...@@ -1806,6 +1852,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
), ),
textDirection: textDirection, textDirection: textDirection,
textBaseline: textBaseline, textBaseline: textBaseline,
isFocused: isFocused,
); );
} }
} }
......
...@@ -2250,4 +2250,68 @@ void main() { ...@@ -2250,4 +2250,68 @@ void main() {
expect(focusNode.hasFocus, isFalse); 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