mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
Fixing a text editing bug happening when text field changes. (#41108)
* Carrying last size and transform information to TextInputConnection. Doing this we are making sure that the size/transform information from the previous connection will be removed, when connection changes. * remove unused lastsize and lasttransform values * Adding unit tests. Adressing comments.
This commit is contained in:
parent
0e6cb28dbe
commit
f6e77a9ee5
|
@ -642,8 +642,11 @@ abstract class TextInputClient {
|
|||
/// * [TextInput.attach]
|
||||
class TextInputConnection {
|
||||
TextInputConnection._(this._client)
|
||||
: assert(_client != null),
|
||||
_id = _nextId++;
|
||||
: assert(_client != null),
|
||||
_id = _nextId++;
|
||||
|
||||
Size _cachedSize;
|
||||
Matrix4 _cachedTransform;
|
||||
|
||||
static int _nextId = 1;
|
||||
final int _id;
|
||||
|
@ -678,14 +681,18 @@ class TextInputConnection {
|
|||
/// 2. [transform]: a matrix that maps the local paint coordinate system
|
||||
/// to the [PipelineOwner.rootNode].
|
||||
void setEditableSizeAndTransform(Size editableBoxSize, Matrix4 transform) {
|
||||
SystemChannels.textInput.invokeMethod<void>(
|
||||
'TextInput.setEditableSizeAndTransform',
|
||||
<String, dynamic>{
|
||||
'width': editableBoxSize.width,
|
||||
'height': editableBoxSize.height,
|
||||
'transform': transform.storage,
|
||||
},
|
||||
);
|
||||
if (editableBoxSize != _cachedSize || transform != _cachedTransform) {
|
||||
_cachedSize = editableBoxSize;
|
||||
_cachedTransform = transform;
|
||||
SystemChannels.textInput.invokeMethod<void>(
|
||||
'TextInput.setEditableSizeAndTransform',
|
||||
<String, dynamic>{
|
||||
'width': editableBoxSize.width,
|
||||
'height': editableBoxSize.height,
|
||||
'transform': transform.storage,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Send text styling information.
|
||||
|
|
|
@ -1703,18 +1703,11 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
|||
updateKeepAlive();
|
||||
}
|
||||
|
||||
Size _lastSize;
|
||||
Matrix4 _lastTransform;
|
||||
|
||||
void _updateSizeAndTransform() {
|
||||
if (_hasInputConnection) {
|
||||
final Size size = renderEditable.size;
|
||||
final Matrix4 transform = renderEditable.getTransformTo(null);
|
||||
if (size != _lastSize || transform != _lastTransform) {
|
||||
_lastSize = size;
|
||||
_lastTransform = transform;
|
||||
_textInputConnection.setEditableSizeAndTransform(size, transform);
|
||||
}
|
||||
_textInputConnection.setEditableSizeAndTransform(size, transform);
|
||||
SchedulerBinding.instance
|
||||
.addPostFrameCallback((Duration _) => _updateSizeAndTransform());
|
||||
}
|
||||
|
|
|
@ -2215,6 +2215,88 @@ void main() {
|
|||
);
|
||||
});
|
||||
|
||||
testWidgets('transform and size is reset when text connection opens', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
final TextEditingController controller1 = TextEditingController();
|
||||
final TextEditingController controller2 = TextEditingController();
|
||||
controller1.text = 'Text1';
|
||||
controller2.text = 'Text2';
|
||||
|
||||
await tester.pumpWidget(
|
||||
MediaQuery(
|
||||
data: const MediaQueryData(
|
||||
devicePixelRatio: 1.0
|
||||
),
|
||||
child: Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
EditableText(
|
||||
key: ValueKey<String>(controller1.text),
|
||||
controller: controller1,
|
||||
focusNode: FocusNode(),
|
||||
style: Typography(platform: TargetPlatform.android).black.subhead,
|
||||
cursorColor: Colors.blue,
|
||||
backgroundCursorColor: Colors.grey,
|
||||
),
|
||||
const SizedBox(height: 200.0),
|
||||
EditableText(
|
||||
key: ValueKey<String>(controller2.text),
|
||||
controller: controller2,
|
||||
focusNode: FocusNode(),
|
||||
style: Typography(platform: TargetPlatform.android).black.subhead,
|
||||
cursorColor: Colors.blue,
|
||||
backgroundCursorColor: Colors.grey,
|
||||
),
|
||||
const SizedBox(height: 100.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.showKeyboard(find.byKey(ValueKey<String>(controller1.text)));
|
||||
final MethodCall methodCall = log.firstWhere((MethodCall m) => m.method == 'TextInput.setEditableSizeAndTransform');
|
||||
expect(
|
||||
methodCall,
|
||||
isMethodCall('TextInput.setEditableSizeAndTransform', arguments: <String, dynamic>{
|
||||
'width': 800,
|
||||
'height': 14,
|
||||
'transform': Matrix4.identity().storage.toList(),
|
||||
}),
|
||||
);
|
||||
|
||||
// Move to the next editable text.
|
||||
await tester.showKeyboard(find.byKey(ValueKey<String>(controller2.text)));
|
||||
final MethodCall methodCall2 = log.firstWhere((MethodCall m) => m.method == 'TextInput.setEditableSizeAndTransform');
|
||||
expect(
|
||||
methodCall2,
|
||||
isMethodCall('TextInput.setEditableSizeAndTransform', arguments: <String, dynamic>{
|
||||
'width': 800,
|
||||
'height': 14,
|
||||
'transform': Matrix4.identity().storage.toList(),
|
||||
}),
|
||||
);
|
||||
|
||||
// Move back to the first editable text.
|
||||
await tester.showKeyboard(find.byKey(ValueKey<String>(controller1.text)));
|
||||
final MethodCall methodCall3 = log.firstWhere((MethodCall m) => m.method == 'TextInput.setEditableSizeAndTransform');
|
||||
expect(
|
||||
methodCall3,
|
||||
isMethodCall('TextInput.setEditableSizeAndTransform', arguments: <String, dynamic>{
|
||||
'width': 800,
|
||||
'height': 14,
|
||||
'transform': Matrix4.identity().storage.toList(),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('size and transform are sent when they change', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
|
|
Loading…
Reference in a new issue