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
ac4d5099
Unverified
Commit
ac4d5099
authored
Feb 24, 2021
by
LongCatIsLooong
Committed by
GitHub
Feb 24, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reland #74722 (#75604)
parent
e07c2483
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
345 additions
and
27 deletions
+345
-27
text_field.dart
packages/flutter/lib/src/cupertino/text_field.dart
+2
-0
text_field.dart
packages/flutter/lib/src/material/text_field.dart
+3
-1
editable.dart
packages/flutter/lib/src/rendering/editable.dart
+11
-10
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+30
-13
text_field_test.dart
packages/flutter/test/material/text_field_test.dart
+55
-2
editable_text_show_on_screen_test.dart
...utter/test/widgets/editable_text_show_on_screen_test.dart
+244
-1
No files found.
packages/flutter/lib/src/cupertino/text_field.dart
View file @
ac4d5099
...
...
@@ -179,6 +179,8 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe
/// Remember to call [TextEditingController.dispose] when it is no longer
/// needed. This will ensure we discard any resources used by the object.
///
/// {@macro flutter.widgets.editableText.showCaretOnScreen}
///
/// See also:
///
/// * <https://developer.apple.com/documentation/uikit/uitextfield>
...
...
packages/flutter/lib/src/material/text_field.dart
View file @
ac4d5099
...
...
@@ -256,7 +256,7 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete
/// Keep in mind you can also always read the current string from a TextField's
/// [TextEditingController] using [TextEditingController.text].
///
/// ## Handling emojis and other complex characters
/// ## Handling emojis and other complex characters
/// {@macro flutter.widgets.EditableText.onChanged}
///
/// In the live Dartpad example above, try typing the emoji 👨👩👦
...
...
@@ -264,6 +264,8 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete
/// with `value.characters.length`, the emoji is correctly counted as a single
/// character.
///
/// {@macro flutter.widgets.editableText.showCaretOnScreen}
///
/// See also:
///
/// * [TextFormField], which integrates with the [Form] widget.
...
...
packages/flutter/lib/src/rendering/editable.dart
View file @
ac4d5099
...
...
@@ -2710,21 +2710,22 @@ class _FloatingCursorPainter extends RenderEditablePainter {
caretRect
=
caretRect
.
shift
(
renderEditable
.
_paintOffset
);
final
Rect
integralRect
=
caretRect
.
shift
(
renderEditable
.
_snapToPhysicalPixel
(
caretRect
.
topLeft
));
final
Radius
?
radius
=
cursorRadius
;
caretPaint
.
color
=
caretColor
;
if
(
radius
==
null
)
{
canvas
.
drawRect
(
integralRect
,
caretPaint
);
}
else
{
final
RRect
caretRRect
=
RRect
.
fromRectAndRadius
(
integralRect
,
radius
);
canvas
.
drawRRect
(
caretRRect
,
caretPaint
);
if
(
shouldPaint
)
{
final
Radius
?
radius
=
cursorRadius
;
caretPaint
.
color
=
caretColor
;
if
(
radius
==
null
)
{
canvas
.
drawRect
(
integralRect
,
caretPaint
);
}
else
{
final
RRect
caretRRect
=
RRect
.
fromRectAndRadius
(
integralRect
,
radius
);
canvas
.
drawRRect
(
caretRRect
,
caretPaint
);
}
}
caretPaintCallback
(
integralRect
);
}
@override
void
paint
(
Canvas
canvas
,
Size
size
,
RenderEditable
renderEditable
)
{
if
(!
shouldPaint
)
return
;
// Compute the caret location even when `shouldPaint` is false.
assert
(
renderEditable
!=
null
);
final
TextSelection
?
selection
=
renderEditable
.
selection
;
...
...
@@ -2749,7 +2750,7 @@ class _FloatingCursorPainter extends RenderEditablePainter {
final
Color
?
floatingCursorColor
=
this
.
caretColor
?.
withOpacity
(
0.75
);
// Floating Cursor.
if
(
floatingCursorRect
==
null
||
floatingCursorColor
==
null
)
if
(
floatingCursorRect
==
null
||
floatingCursorColor
==
null
||
!
shouldPaint
)
return
;
canvas
.
drawRRect
(
...
...
packages/flutter/lib/src/widgets/editable_text.dart
View file @
ac4d5099
...
...
@@ -398,6 +398,18 @@ class ToolbarOptions {
/// methods such as [RenderEditable.selectPosition],
/// [RenderEditable.selectWord], etc. programmatically.
///
/// {@template flutter.widgets.editableText.showCaretOnScreen}
/// ## Keep the caret visisble when focused
///
/// When focused, this widget will make attempts to keep the text area and its
/// caret (even when [showCursor] is `false`) visible, on these occasions:
///
/// * When the user focuses this text field and it is not [readOnly].
/// * When the user changes the selection of the text field, or changes the
/// text when the text field is not [readOnly].
/// * When the virtual keyboard pops up.
/// {@endtemplate}
///
/// See also:
///
/// * [TextField], which is a full-featured, material-design text input field
...
...
@@ -1721,7 +1733,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_currentPromptRectRange
=
null
;
if
(
_hasInputConnection
)
{
_showCaretOnScreen
();
if
(
widget
.
obscureText
&&
value
.
text
.
length
==
_value
.
text
.
length
+
1
)
{
_obscureShowCharTicksPending
=
_kObscureShowLatestCharCursorTicks
;
_obscureLatestCharIndex
=
_value
.
selection
.
baseOffset
;
...
...
@@ -1731,6 +1742,11 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_formatAndSetValue
(
value
);
}
// Wherever the value is changed by the user, schedule a showCaretOnScreen
// to make sure the user can see the changes they just made. Programmatical
// changes to `textEditingValue` do not trigger the behavior even if the
// text field is focused.
_scheduleShowCaretOnScreen
();
if
(
_hasInputConnection
)
{
// To keep the cursor from blinking while typing, we want to restart the
// cursor timer every time a new character is typed.
...
...
@@ -2154,17 +2170,9 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
}
bool
_textChangedSinceLastCaretUpdate
=
false
;
Rect
?
_currentCaretRect
;
void
_handleCaretChanged
(
Rect
caretRect
)
{
_currentCaretRect
=
caretRect
;
// If the caret location has changed due to an update to the text or
// selection, then scroll the caret into view.
if
(
_textChangedSinceLastCaretUpdate
)
{
_textChangedSinceLastCaretUpdate
=
false
;
_showCaretOnScreen
();
}
}
// Animation configuration for scrolling the caret back on screen.
...
...
@@ -2173,7 +2181,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
bool
_showCaretOnScreenScheduled
=
false
;
void
_showCaretOnScreen
()
{
void
_s
cheduleS
howCaretOnScreen
()
{
if
(
_showCaretOnScreenScheduled
)
{
return
;
}
...
...
@@ -2232,7 +2240,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
@override
void
didChangeMetrics
()
{
if
(
_lastBottomViewInset
<
WidgetsBinding
.
instance
!.
window
.
viewInsets
.
bottom
)
{
_showCaretOnScreen
();
_s
cheduleS
howCaretOnScreen
();
}
_lastBottomViewInset
=
WidgetsBinding
.
instance
!.
window
.
viewInsets
.
bottom
;
}
...
...
@@ -2390,7 +2398,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_updateRemoteEditingValueIfNeeded
();
_startOrStopCursorTimerIfNeeded
();
_updateOrDisposeSelectionOverlayIfNeeded
();
_textChangedSinceLastCaretUpdate
=
true
;
// TODO(abarth): Teach RenderEditable about ValueNotifier<TextEditingValue>
// to avoid this setState().
setState
(()
{
/* We use widget.controller.value in build(). */
});
...
...
@@ -2404,7 +2411,9 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
// Listen for changing viewInsets, which indicates keyboard showing up.
WidgetsBinding
.
instance
!.
addObserver
(
this
);
_lastBottomViewInset
=
WidgetsBinding
.
instance
!.
window
.
viewInsets
.
bottom
;
_showCaretOnScreen
();
if
(!
widget
.
readOnly
)
{
_scheduleShowCaretOnScreen
();
}
if
(!
_value
.
selection
.
isValid
)
{
// Place cursor at the end if the selection is invalid when we receive focus.
_handleSelectionChanged
(
TextSelection
.
collapsed
(
offset:
_value
.
text
.
length
),
renderEditable
,
null
);
...
...
@@ -2471,6 +2480,14 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
@override
set
textEditingValue
(
TextEditingValue
value
)
{
_selectionOverlay
?.
update
(
value
);
// Compare the current TextEditingValue with the pre-format new
// TextEditingValue value, in case the formatter would reject the change.
final
bool
shouldShowCaret
=
widget
.
readOnly
?
_value
.
selection
!=
value
.
selection
:
_value
!=
value
;
if
(
shouldShowCaret
)
{
_scheduleShowCaretOnScreen
();
}
_formatAndSetValue
(
value
);
}
...
...
packages/flutter/test/material/text_field_test.dart
View file @
ac4d5099
...
...
@@ -3495,7 +3495,12 @@ void main() {
// Move the caret to the end of the text and check that the text field
// scrolls to make the caret visible.
controller
.
selection
=
TextSelection
.
collapsed
(
offset:
longText
.
length
);
scrollableState
=
tester
.
firstState
(
find
.
byType
(
Scrollable
));
final
EditableTextState
editableTextState
=
tester
.
firstState
(
find
.
byType
(
EditableText
));
editableTextState
.
textEditingValue
=
editableTextState
.
textEditingValue
.
copyWith
(
selection:
TextSelection
.
collapsed
(
offset:
longText
.
length
),
);
await
tester
.
pump
();
// TODO(ianh): Figure out why this extra pump is needed.
await
skipPastScrollingAnimation
(
tester
);
...
...
@@ -3527,7 +3532,10 @@ void main() {
// Move the caret to the end of the text and check that the text field
// scrolls to make the caret visible.
controller
.
selection
=
const
TextSelection
.
collapsed
(
offset:
tallText
.
length
);
final
EditableTextState
editableTextState
=
tester
.
firstState
(
find
.
byType
(
EditableText
));
editableTextState
.
textEditingValue
=
editableTextState
.
textEditingValue
.
copyWith
(
selection:
const
TextSelection
.
collapsed
(
offset:
tallText
.
length
),
);
await
tester
.
pump
();
await
skipPastScrollingAnimation
(
tester
);
...
...
@@ -8614,6 +8622,51 @@ void main() {
expect
(
scrollController
.
offset
,
48.0
);
});
// Regression test for https://github.com/flutter/flutter/issues/74566
testWidgets
(
'TextField and last input character are visible on the screen when the cursor is not shown'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
scrollController
=
ScrollController
();
final
ScrollController
textFieldScrollController
=
ScrollController
();
await
tester
.
pumpWidget
(
MaterialApp
(
theme:
ThemeData
(),
home:
Scaffold
(
body:
Center
(
child:
ListView
(
controller:
scrollController
,
children:
<
Widget
>[
Container
(
height:
579
),
// Push field almost off screen.
TextField
(
scrollController:
textFieldScrollController
,
showCursor:
false
,
),
Container
(
height:
1000
),
],
),
),
),
));
// Tap the TextField to bring it into view.
expect
(
scrollController
.
offset
,
0.0
);
await
tester
.
tapAt
(
tester
.
getTopLeft
(
find
.
byType
(
TextField
)));
await
tester
.
pumpAndSettle
();
// The ListView has scrolled to keep the TextField visible.
expect
(
scrollController
.
offset
,
48.0
);
expect
(
textFieldScrollController
.
offset
,
0.0
);
// After entering some long text, the last input character remains on the screen.
final
String
testValue
=
'I love Flutter!'
*
10
;
tester
.
testTextInput
.
updateEditingValue
(
TextEditingValue
(
text:
testValue
,
selection:
TextSelection
.
collapsed
(
offset:
testValue
.
length
),
));
await
tester
.
pump
();
await
tester
.
pumpAndSettle
();
// Text scroll animation.
expect
(
textFieldScrollController
.
offset
,
1602.0
);
});
group
(
'height'
,
()
{
testWidgets
(
'By default, TextField is at least kMinInteractiveDimension high'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
...
...
packages/flutter/test/widgets/editable_text_show_on_screen_test.dart
View file @
ac4d5099
This diff is collapsed.
Click to expand it.
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