From 2e883f8552682f9ac799f91eb96ffdf896d821a2 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Sun, 6 Jan 2019 16:38:13 -0800 Subject: [PATCH] Skip formatters if text has not changed (#24779) --- .../lib/src/widgets/editable_text.dart | 2 +- .../test/widgets/editable_text_test.dart | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index bd60ca881ba..bd22473fe4d 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -914,7 +914,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien void _formatAndSetValue(TextEditingValue value) { final bool textChanged = _value?.text != value?.text; - if (widget.inputFormatters != null && widget.inputFormatters.isNotEmpty) { + if (textChanged && widget.inputFormatters != null && widget.inputFormatters.isNotEmpty) { for (TextInputFormatter formatter in widget.inputFormatters) value = formatter.formatEditUpdate(_value, value); _value = value; diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 85ae629af54..a2110a0ef4a 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -1938,6 +1938,47 @@ testWidgets( expect(controller.selection.baseOffset, 11); }); + + testWidgets('Formatters are skipped if text has not changed', (WidgetTester tester) async { + int called = 0; + final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) { + called += 1; + return newValue; + }); + final TextEditingController controller = TextEditingController(); + final EditableText editableText = EditableText( + controller: controller, + backgroundCursorColor: Colors.red, + cursorColor: Colors.red, + focusNode: FocusNode(), + style: textStyle, + inputFormatters: [ + formatter, + ], + textDirection: TextDirection.ltr, + ); + await tester.pumpWidget(editableText); + final EditableTextState state = tester.firstState(find.byType(EditableText)); + state.updateEditingValue(const TextEditingValue( + text: 'a', + )); + expect(called, 1); + // same value. + state.updateEditingValue(const TextEditingValue( + text: 'a', + )); + expect(called, 1); + // same value with different selection. + state.updateEditingValue(const TextEditingValue( + text: 'a', + selection: TextSelection.collapsed(offset: 1), + )); + // different value. + state.updateEditingValue(const TextEditingValue( + text: 'b', + )); + expect(called, 2); + }); } class MockTextSelectionControls extends Mock implements TextSelectionControls {}