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
746056a5
Unverified
Commit
746056a5
authored
Dec 03, 2020
by
LongCatIsLooong
Committed by
GitHub
Dec 03, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Skip reformatting and calling onChanged for composing region only changes. (#70883)
parent
8e05e59c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
32 additions
and
18 deletions
+32
-18
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+24
-11
editable_text_test.dart
packages/flutter/test/widgets/editable_text_test.dart
+8
-7
No files found.
packages/flutter/lib/src/widgets/editable_text.dart
View file @
746056a5
...
...
@@ -69,12 +69,21 @@ const int _kObscureShowLatestCharCursorTicks = 3;
/// text field. If you build a text field with a controller that already has
/// [text], the text field will use that text as its initial value.
///
/// The [text] or [selection] properties can be set from within a listener
/// added to this controller. If both properties need to be changed then the
/// controller's [value] should be set instead.
/// The [value] (as well as [text] and [selection]) of this controller can be
/// updated from within a listener added to this controller. Be aware of
/// infinite loops since the listener will also be notified of the changes made
/// from within itself. Modifying the composing region from within a listener
/// can also have a bad interaction with some input methods. Gboard, for
/// example, will try to restore the composing region of the text if it was
/// modified programmatically, creating an infinite loop of communications
/// between the framework and the input method. Consider using
/// [TextInputFormatter]s instead for as-you-type text modification.
///
/// Remember to [dispose] of the [TextEditingController] when it is no longer needed.
/// This will ensure we discard any resources used by the object.
/// If both the [text] or [selection] properties need to be changed, set the
/// controller's [value] instead.
///
/// Remember to [dispose] of the [TextEditingController] when it is no longer
/// needed. This will ensure we discard any resources used by the object.
/// {@tool dartpad --template=stateful_widget_material}
/// This example creates a [TextField] with a [TextEditingController] whose
/// change listener forces the entered text to be lower case and keeps the
...
...
@@ -2183,14 +2192,18 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
late
final
_WhitespaceDirectionalityFormatter
_whitespaceFormatter
=
_WhitespaceDirectionalityFormatter
(
textDirection:
_textDirection
);
void
_formatAndSetValue
(
TextEditingValue
value
)
{
// Check if the new value is the same as the current local value, or is the same
// as the pre-formatting value of the previous pass (repeat call).
final
bool
textChanged
=
_value
.
text
!=
value
.
text
||
_value
.
composing
!=
value
.
composing
;
// Only apply input formatters if the text has changed (including uncommited
// 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
);
if
(
textChanged
)
{
// Only format when the text has changed and there are available formatters.
// Pass through the formatter regardless of repeat status if the input value is
// different than the stored value.
value
=
widget
.
inputFormatters
?.
fold
<
TextEditingValue
>(
value
,
(
TextEditingValue
newValue
,
TextInputFormatter
formatter
)
=>
formatter
.
formatEditUpdate
(
_value
,
newValue
),
...
...
packages/flutter/test/widgets/editable_text_test.dart
View file @
746056a5
...
...
@@ -5835,12 +5835,15 @@ void main() {
expect
(
formatter
.
formatCallCount
,
3
);
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'0123'
,
selection:
TextSelection
.
collapsed
(
offset:
2
)));
// No text change, does not format
expect
(
formatter
.
formatCallCount
,
3
);
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'0123'
,
selection:
TextSelection
.
collapsed
(
offset:
2
),
composing:
TextRange
(
start:
1
,
end:
2
)));
// Composing change triggers reformat
expect
(
formatter
.
formatCallCount
,
4
);
// Composing changes should not trigger reformat, as it could cause infinite loops on some IMEs.
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'0123'
,
selection:
TextSelection
.
collapsed
(
offset:
2
),
composing:
TextRange
(
start:
1
,
end:
2
)));
expect
(
formatter
.
formatCallCount
,
3
);
expect
(
formatter
.
lastOldValue
.
composing
,
const
TextRange
(
start:
-
1
,
end:
-
1
));
expect
(
formatter
.
lastNewValue
.
composing
,
const
TextRange
(
start:
1
,
end:
2
));
// The new composing was registered in formatter.
expect
(
formatter
.
lastNewValue
.
composing
,
const
TextRange
(
start:
-
1
,
end:
-
1
));
// The new composing was registered in formatter.
// Clearing composing region should trigger reformat.
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'01234'
,
selection:
TextSelection
.
collapsed
(
offset:
2
)));
// Formats, with oldValue containing composing region.
expect
(
formatter
.
formatCallCount
,
5
);
expect
(
formatter
.
formatCallCount
,
4
);
expect
(
formatter
.
lastOldValue
.
composing
,
const
TextRange
(
start:
1
,
end:
2
));
expect
(
formatter
.
lastNewValue
.
composing
,
const
TextRange
(
start:
-
1
,
end:
-
1
));
...
...
@@ -5851,10 +5854,8 @@ void main() {
'[2]: normal aaaa'
,
'[3]: 012, 0123'
,
'[3]: normal aaaaaa'
,
'[4]: 0123, 0123'
,
'[4]: 0123, 0123
4
'
,
'[4]: normal aaaaaaaa'
,
'[5]: 0123, 01234'
,
'[5]: normal aaaaaaaaaa'
,
];
expect
(
formatter
.
log
,
referenceLog
);
...
...
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