TextField should update IME when controller changes (#9261)
Fixes #9246
This commit is contained in:
parent
249bbac362
commit
470db7d96e
@ -239,9 +239,8 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
|
|||||||
if (config.controller != oldConfig.controller) {
|
if (config.controller != oldConfig.controller) {
|
||||||
oldConfig.controller.removeListener(_didChangeTextEditingValue);
|
oldConfig.controller.removeListener(_didChangeTextEditingValue);
|
||||||
config.controller.addListener(_didChangeTextEditingValue);
|
config.controller.addListener(_didChangeTextEditingValue);
|
||||||
if (_hasInputConnection && config.controller.value != oldConfig.controller.value)
|
_updateRemoteEditingValueIfNeeded();
|
||||||
_textInputConnection.setEditingState(config.controller.value);
|
}
|
||||||
}
|
|
||||||
if (config.focusNode != oldConfig.focusNode) {
|
if (config.focusNode != oldConfig.focusNode) {
|
||||||
oldConfig.focusNode.removeListener(_handleFocusChanged);
|
oldConfig.focusNode.removeListener(_handleFocusChanged);
|
||||||
config.focusNode.addListener(_handleFocusChanged);
|
config.focusNode.addListener(_handleFocusChanged);
|
||||||
@ -263,10 +262,13 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
|
|||||||
|
|
||||||
// TextInputClient implementation:
|
// TextInputClient implementation:
|
||||||
|
|
||||||
|
TextEditingValue _lastKnownRemoteTextEditingValue;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void updateEditingValue(TextEditingValue value) {
|
void updateEditingValue(TextEditingValue value) {
|
||||||
if (value.text != _value.text)
|
if (value.text != _value.text)
|
||||||
_hideSelectionOverlayIfNeeded();
|
_hideSelectionOverlayIfNeeded();
|
||||||
|
_lastKnownRemoteTextEditingValue = value;
|
||||||
_value = value;
|
_value = value;
|
||||||
if (config.onChanged != null)
|
if (config.onChanged != null)
|
||||||
config.onChanged(value.text);
|
config.onChanged(value.text);
|
||||||
@ -280,6 +282,16 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
|
|||||||
config.onSubmitted(_value.text);
|
config.onSubmitted(_value.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _updateRemoteEditingValueIfNeeded() {
|
||||||
|
if (!_hasInputConnection)
|
||||||
|
return;
|
||||||
|
final TextEditingValue localValue = _value;
|
||||||
|
if (localValue == _lastKnownRemoteTextEditingValue)
|
||||||
|
return;
|
||||||
|
_lastKnownRemoteTextEditingValue = localValue;
|
||||||
|
_textInputConnection.setEditingState(localValue);
|
||||||
|
}
|
||||||
|
|
||||||
TextEditingValue get _value => config.controller.value;
|
TextEditingValue get _value => config.controller.value;
|
||||||
set _value(TextEditingValue value) {
|
set _value(TextEditingValue value) {
|
||||||
config.controller.value = value;
|
config.controller.value = value;
|
||||||
@ -306,8 +318,10 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
|
|||||||
|
|
||||||
void _openInputConnectionIfNeeded() {
|
void _openInputConnectionIfNeeded() {
|
||||||
if (!_hasInputConnection) {
|
if (!_hasInputConnection) {
|
||||||
|
final TextEditingValue localValue = _value;
|
||||||
|
_lastKnownRemoteTextEditingValue = localValue;
|
||||||
_textInputConnection = TextInput.attach(this, new TextInputConfiguration(inputType: config.keyboardType))
|
_textInputConnection = TextInput.attach(this, new TextInputConfiguration(inputType: config.keyboardType))
|
||||||
..setEditingState(_value)
|
..setEditingState(localValue)
|
||||||
..show();
|
..show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,6 +330,7 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
|
|||||||
if (_hasInputConnection) {
|
if (_hasInputConnection) {
|
||||||
_textInputConnection.close();
|
_textInputConnection.close();
|
||||||
_textInputConnection = null;
|
_textInputConnection = null;
|
||||||
|
_lastKnownRemoteTextEditingValue = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,6 +444,7 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _didChangeTextEditingValue() {
|
void _didChangeTextEditingValue() {
|
||||||
|
_updateRemoteEditingValueIfNeeded();
|
||||||
_startOrStopCursorTimerIfNeeded();
|
_startOrStopCursorTimerIfNeeded();
|
||||||
_updateOrDisposeSelectionOverlayIfNeeded();
|
_updateOrDisposeSelectionOverlayIfNeeded();
|
||||||
// TODO(abarth): Teach RenderEditable about ValueNotifier<TextEditingValue>
|
// TODO(abarth): Teach RenderEditable about ValueNotifier<TextEditingValue>
|
||||||
|
@ -886,4 +886,59 @@ void main() {
|
|||||||
|
|
||||||
expect(topLeft.x, equals(399.0));
|
expect(topLeft.x, equals(399.0));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Controller can update server', (WidgetTester tester) async {
|
||||||
|
final TextEditingController controller = new TextEditingController(
|
||||||
|
text: 'Initial Text',
|
||||||
|
);
|
||||||
|
final TextEditingController controller2 = new TextEditingController(
|
||||||
|
text: 'More Text',
|
||||||
|
);
|
||||||
|
|
||||||
|
TextEditingController currentController = controller;
|
||||||
|
StateSetter setState;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
overlay(new Center(
|
||||||
|
child: new Material(
|
||||||
|
child: new StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setter) {
|
||||||
|
setState = setter;
|
||||||
|
return new TextField(controller: currentController);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.testTextInput.editingState['text'], isEmpty);
|
||||||
|
|
||||||
|
await tester.tap(find.byType(TextField));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(tester.testTextInput.editingState['text'], equals('Initial Text'));
|
||||||
|
|
||||||
|
controller.text = 'Updated Text';
|
||||||
|
await tester.idle();
|
||||||
|
|
||||||
|
expect(tester.testTextInput.editingState['text'], equals('Updated Text'));
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
currentController = controller2;
|
||||||
|
});
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(tester.testTextInput.editingState['text'], equals('More Text'));
|
||||||
|
|
||||||
|
controller.text = 'Ignored Text';
|
||||||
|
await tester.idle();
|
||||||
|
|
||||||
|
expect(tester.testTextInput.editingState['text'], equals('More Text'));
|
||||||
|
|
||||||
|
controller2.text = 'Final Text';
|
||||||
|
await tester.idle();
|
||||||
|
|
||||||
|
expect(tester.testTextInput.editingState['text'], equals('Final Text'));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user