Toggle whether label or hint contribute to text field semantics when unfocused/focused (#19790)
This commit is contained in:
parent
6dc18525c2
commit
ffdd6e1bf1
@ -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 {
|
|||||||
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 {
|
|||||||
_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 {
|
|||||||
@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 {
|
|||||||
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 {
|
|||||||
decoration: decoration,
|
decoration: decoration,
|
||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
textBaseline: textBaseline,
|
textBaseline: textBaseline,
|
||||||
|
isFocused: isFocused,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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
|
|||||||
? 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
|
|||||||
),
|
),
|
||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
textBaseline: textBaseline,
|
textBaseline: textBaseline,
|
||||||
|
isFocused: isFocused,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user