Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
72707416
Unverified
Commit
72707416
authored
Sep 21, 2022
by
LongCatIsLooong
Committed by
GitHub
Sep 21, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Prevent committing text from triggering EditableText.onChanged (#112010)
parent
c34e9071
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
63 additions
and
16 deletions
+63
-16
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+17
-16
editable_text_test.dart
packages/flutter/test/widgets/editable_text_test.dart
+46
-0
No files found.
packages/flutter/lib/src/widgets/editable_text.dart
View file @
72707416
...
...
@@ -2924,19 +2924,20 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
@pragma
(
'vm:notify-debugger-on-exception'
)
void
_formatAndSetValue
(
TextEditingValue
value
,
SelectionChangedCause
?
cause
,
{
bool
userInteraction
=
false
})
{
// Only apply input formatters if the text has changed (including uncommitted
// text in the composing region), or when the user committed the composing
// text.
// Gboard is very persistent in restoring the composing region. Applying
// input formatters on composing-region-only changes (except clearing the
// current composing region) is very infinite-loop-prone: the formatters
// will keep trying to modify the composing region while Gboard will keep
// trying to restore the original composing region.
final
bool
textChanged
=
_value
.
text
!=
value
.
text
||
(!
_value
.
composing
.
isCollapsed
&&
value
.
composing
.
isCollapsed
);
final
bool
selectionChanged
=
_value
.
selection
!=
value
.
selection
;
if
(
textChanged
)
{
final
TextEditingValue
oldValue
=
_value
;
final
bool
textChanged
=
oldValue
.
text
!=
value
.
text
;
final
bool
textCommitted
=
!
oldValue
.
composing
.
isCollapsed
&&
value
.
composing
.
isCollapsed
;
final
bool
selectionChanged
=
oldValue
.
selection
!=
value
.
selection
;
if
(
textChanged
||
textCommitted
)
{
// Only apply input formatters if the text has changed (including uncommitted
// text in the composing region), or when the user committed the composing
// text.
// Gboard is very persistent in restoring the composing region. Applying
// input formatters on composing-region-only changes (except clearing the
// current composing region) is very infinite-loop-prone: the formatters
// will keep trying to modify the composing region while Gboard will keep
// trying to restore the original composing region.
try
{
value
=
widget
.
inputFormatters
?.
fold
<
TextEditingValue
>(
value
,
...
...
@@ -2970,9 +2971,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
cause
==
SelectionChangedCause
.
keyboard
)))
{
_handleSelectionChanged
(
_value
.
selection
,
cause
);
}
if
(
textChanged
)
{
final
String
currentText
=
_value
.
text
;
if
(
oldValue
.
text
!=
currentText
)
{
try
{
widget
.
onChanged
?.
call
(
_value
.
t
ext
);
widget
.
onChanged
?.
call
(
currentT
ext
);
}
catch
(
exception
,
stack
)
{
FlutterError
.
reportError
(
FlutterErrorDetails
(
exception:
exception
,
...
...
@@ -2982,7 +2984,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
));
}
}
endBatchEdit
();
}
...
...
packages/flutter/test/widgets/editable_text_test.dart
View file @
72707416
...
...
@@ -4312,6 +4312,52 @@ void main() {
expect
(
render
.
text
!.
style
!.
fontStyle
,
FontStyle
.
italic
);
});
testWidgets
(
'onChanged callback only invoked on text changes'
,
(
WidgetTester
tester
)
async
{
// Regression test for https://github.com/flutter/flutter/issues/111651 .
final
TextEditingController
controller
=
TextEditingController
();
int
onChangedCount
=
0
;
bool
preventInput
=
false
;
final
TextInputFormatter
formatter
=
TextInputFormatter
.
withFunction
((
TextEditingValue
oldValue
,
TextEditingValue
newValue
)
{
return
preventInput
?
oldValue
:
newValue
;
});
final
Widget
widget
=
MediaQuery
(
data:
const
MediaQueryData
(),
child:
EditableText
(
controller:
controller
,
backgroundCursorColor:
Colors
.
red
,
cursorColor:
Colors
.
red
,
focusNode:
FocusNode
(),
style:
textStyle
,
onChanged:
(
String
newString
)
{
onChangedCount
+=
1
;
},
inputFormatters:
<
TextInputFormatter
>[
formatter
],
textDirection:
TextDirection
.
ltr
,
),
);
await
tester
.
pumpWidget
(
widget
);
final
EditableTextState
state
=
tester
.
firstState
(
find
.
byType
(
EditableText
));
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'a'
,
composing:
TextRange
(
start:
0
,
end:
1
)),
);
expect
(
onChangedCount
,
1
);
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'a'
),
);
expect
(
onChangedCount
,
1
);
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'ab'
),
);
expect
(
onChangedCount
,
2
);
preventInput
=
true
;
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'abc'
),
);
expect
(
onChangedCount
,
2
);
});
testWidgets
(
'Formatters are skipped if text has not changed'
,
(
WidgetTester
tester
)
async
{
int
called
=
0
;
final
TextInputFormatter
formatter
=
TextInputFormatter
.
withFunction
((
TextEditingValue
oldValue
,
TextEditingValue
newValue
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment