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
2c3652b8
Unverified
Commit
2c3652b8
authored
Aug 24, 2020
by
Alex Li
Committed by
GitHub
Aug 24, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[EditableText] Fix TextField crashed with composing and maxLength set (#63754)
parent
acd82534
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
99 additions
and
2 deletions
+99
-2
text_formatter.dart
packages/flutter/lib/src/services/text_formatter.dart
+20
-1
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+8
-1
editable_text_test.dart
packages/flutter/test/widgets/editable_text_test.dart
+34
-0
form_test.dart
packages/flutter/test/widgets/form_test.dart
+37
-0
No files found.
packages/flutter/lib/src/services/text_formatter.dart
View file @
2c3652b8
...
...
@@ -341,6 +341,15 @@ class LengthLimitingTextInputFormatter extends TextInputFormatter {
/// counted as a single character, but because it is a combination of two
/// Unicode scalar values, '\u{1F44D}\u{1F3FD}', it is counted as two
/// characters.
///
/// ### Composing text behaviors
///
/// There is no guarantee for the final value before the composing ends.
/// So while the value is composing, the constraint of [maxLength] will be
/// temporary lifted until the composing ends.
///
/// In addition, if the current value already reached the [maxLength],
/// composing is not allowed.
final
int
?
maxLength
;
/// Truncate the given TextEditingValue to maxLength characters.
...
...
@@ -367,9 +376,19 @@ class LengthLimitingTextInputFormatter extends TextInputFormatter {
@override
TextEditingValue
formatEditUpdate
(
TextEditingValue
oldValue
,
// unused.
TextEditingValue
oldValue
,
TextEditingValue
newValue
,
)
{
// Return the new value when the old value has not reached the max
// limit or the old value is composing too.
if
(
newValue
.
composing
.
isValid
)
{
if
(
maxLength
!=
null
&&
maxLength
!
>
0
&&
oldValue
.
text
.
characters
.
length
==
maxLength
!
&&
!
oldValue
.
composing
.
isValid
)
{
return
oldValue
;
}
return
newValue
;
}
if
(
maxLength
!=
null
&&
maxLength
!
>
0
&&
newValue
.
text
.
characters
.
length
>
maxLength
!)
{
// If already at the maximum and tried to enter even more, keep the old
// value.
...
...
packages/flutter/lib/src/widgets/editable_text.dart
View file @
2c3652b8
...
...
@@ -2100,7 +2100,14 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
final
bool
textChanged
=
_value
?.
text
!=
value
?.
text
;
final
bool
isRepeat
=
value
==
_lastFormattedUnmodifiedTextEditingValue
;
if
(
textChanged
&&
widget
.
inputFormatters
!=
null
&&
widget
.
inputFormatters
.
isNotEmpty
)
{
// There's no need to format when starting to compose or when continuing
// an existing composition.
final
bool
isComposing
=
value
?.
composing
?.
isValid
??
false
;
final
bool
isPreviouslyComposing
=
_lastFormattedUnmodifiedTextEditingValue
?.
composing
?.
isValid
??
false
;
if
((
textChanged
||
(!
isComposing
&&
isPreviouslyComposing
))
&&
widget
.
inputFormatters
!=
null
&&
widget
.
inputFormatters
.
isNotEmpty
)
{
// 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.
...
...
packages/flutter/test/widgets/editable_text_test.dart
View file @
2c3652b8
...
...
@@ -5341,6 +5341,40 @@ void main() {
expectToAssert
(
const
TextEditingValue
(
text:
'test'
,
composing:
TextRange
(
start:
1
,
end:
9
)),
true
);
expectToAssert
(
const
TextEditingValue
(
text:
'test'
,
composing:
TextRange
(
start:
-
1
,
end:
9
)),
false
);
});
// Regression test for https://github.com/flutter/flutter/issues/65374.
testWidgets
(
'Length formatter will not cause crash while the TextEditingValue is composing'
,
(
WidgetTester
tester
)
async
{
final
TextInputFormatter
formatter
=
LengthLimitingTextInputFormatter
(
5
);
final
Widget
widget
=
MaterialApp
(
home:
EditableText
(
backgroundCursorColor:
Colors
.
grey
,
controller:
controller
,
focusNode:
focusNode
,
inputFormatters:
<
TextInputFormatter
>[
formatter
],
style:
textStyle
,
cursorColor:
cursorColor
,
selectionControls:
materialTextSelectionControls
,
),
);
await
tester
.
pumpWidget
(
widget
);
final
EditableTextState
state
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'12345'
));
expect
(
state
.
currentTextEditingValue
.
composing
,
TextRange
.
empty
);
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'12345'
,
composing:
TextRange
(
start:
2
,
end:
4
)));
expect
(
state
.
currentTextEditingValue
.
composing
,
const
TextRange
(
start:
2
,
end:
4
));
// Formatter will not update format while the editing value is composing.
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'123456'
,
composing:
TextRange
(
start:
2
,
end:
5
)));
expect
(
state
.
currentTextEditingValue
.
text
,
'123456'
);
expect
(
state
.
currentTextEditingValue
.
composing
,
const
TextRange
(
start:
2
,
end:
5
));
// After composing ends, formatter will update.
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'123456'
));
expect
(
state
.
currentTextEditingValue
.
text
,
'12345'
);
expect
(
state
.
currentTextEditingValue
.
composing
,
TextRange
.
empty
);
});
}
class
MockTextFormatter
extends
TextInputFormatter
{
...
...
packages/flutter/test/widgets/form_test.dart
View file @
2c3652b8
...
...
@@ -849,4 +849,41 @@ void main() {
}
expect
(()
=>
builder
(),
throwsAssertionError
);
});
// Regression test for https://github.com/flutter/flutter/issues/65374.
testWidgets
(
'Validate form should return correct validation if the value is composing'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
FormState
>
formKey
=
GlobalKey
<
FormState
>();
String
fieldValue
;
final
Widget
widget
=
MaterialApp
(
home:
MediaQuery
(
data:
const
MediaQueryData
(
devicePixelRatio:
1.0
),
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Center
(
child:
Material
(
child:
Form
(
key:
formKey
,
child:
TextFormField
(
maxLength:
5
,
onSaved:
(
String
value
)
{
fieldValue
=
value
;
},
validator:
(
String
value
)
=>
value
.
length
>
5
?
'Exceeded'
:
null
,
),
),
),
),
),
),
);
await
tester
.
pumpWidget
(
widget
);
final
EditableTextState
editableText
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
editableText
.
updateEditingValue
(
const
TextEditingValue
(
text:
'123456'
,
composing:
TextRange
(
start:
2
,
end:
5
)));
expect
(
editableText
.
currentTextEditingValue
.
composing
,
const
TextRange
(
start:
2
,
end:
5
));
formKey
.
currentState
.
save
();
expect
(
fieldValue
,
'123456'
);
expect
(
formKey
.
currentState
.
validate
(),
isFalse
);
});
}
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