@@ -33,6 +33,7 @@ import 'media_query.dart';
33
33
import 'scroll_configuration.dart' ;
34
34
import 'scroll_controller.dart' ;
35
35
import 'scroll_physics.dart' ;
36
+ import 'scroll_position.dart' ;
36
37
import 'scrollable.dart' ;
37
38
import 'shortcuts.dart' ;
38
39
import 'spell_check.dart' ;
@@ -1907,6 +1908,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
1907
1908
1908
1909
TextSelectionOverlay ? _selectionOverlay;
1909
1910
1911
+ final GlobalKey _scrollableKey = GlobalKey ();
1910
1912
ScrollController ? _internalScrollController;
1911
1913
ScrollController get _scrollController => widget.scrollController ?? (_internalScrollController ?? = ScrollController ());
1912
1914
@@ -3953,6 +3955,96 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
3953
3955
}
3954
3956
}
3955
3957
3958
+ /// Handles [ScrollIntent] by scrolling the [Scrollable] inside of
3959
+ /// [EditableText] .
3960
+ void _scroll (ScrollIntent intent) {
3961
+ if (intent.type != ScrollIncrementType .page) {
3962
+ return ;
3963
+ }
3964
+
3965
+ final ScrollPosition position = _scrollController.position;
3966
+ if (widget.maxLines == 1 ) {
3967
+ _scrollController.jumpTo (position.maxScrollExtent);
3968
+ return ;
3969
+ }
3970
+
3971
+ // If the field isn't scrollable, do nothing. For example, when the lines of
3972
+ // text is less than maxLines, the field has nothing to scroll.
3973
+ if (position.maxScrollExtent == 0.0 && position.minScrollExtent == 0.0 ) {
3974
+ return ;
3975
+ }
3976
+
3977
+ final ScrollableState ? state = _scrollableKey.currentState as ScrollableState ? ;
3978
+ final double increment = ScrollAction .getDirectionalIncrement (state! , intent);
3979
+ final double destination = clampDouble (
3980
+ position.pixels + increment,
3981
+ position.minScrollExtent,
3982
+ position.maxScrollExtent,
3983
+ );
3984
+ if (destination == position.pixels) {
3985
+ return ;
3986
+ }
3987
+ _scrollController.jumpTo (destination);
3988
+ }
3989
+
3990
+ /// Extend the selection down by page if the `forward` parameter is true, or
3991
+ /// up by page otherwise.
3992
+ void _extendSelectionByPage (ExtendSelectionByPageIntent intent) {
3993
+ if (widget.maxLines == 1 ) {
3994
+ return ;
3995
+ }
3996
+
3997
+ final TextSelection nextSelection;
3998
+ final Rect extentRect = renderEditable.getLocalRectForCaret (
3999
+ _value.selection.extent,
4000
+ );
4001
+ final ScrollableState ? state = _scrollableKey.currentState as ScrollableState ? ;
4002
+ final double increment = ScrollAction .getDirectionalIncrement (
4003
+ state! ,
4004
+ ScrollIntent (
4005
+ direction: intent.forward ? AxisDirection .down : AxisDirection .up,
4006
+ type: ScrollIncrementType .page,
4007
+ ),
4008
+ );
4009
+ final ScrollPosition position = _scrollController.position;
4010
+ if (intent.forward) {
4011
+ if (_value.selection.extentOffset >= _value.text.length) {
4012
+ return ;
4013
+ }
4014
+ final Offset nextExtentOffset =
4015
+ Offset (extentRect.left, extentRect.top + increment);
4016
+ final double height = position.maxScrollExtent + renderEditable.size.height;
4017
+ final TextPosition nextExtent = nextExtentOffset.dy + position.pixels >= height
4018
+ ? TextPosition (offset: _value.text.length)
4019
+ : renderEditable.getPositionForPoint (
4020
+ renderEditable.localToGlobal (nextExtentOffset),
4021
+ );
4022
+ nextSelection = _value.selection.copyWith (
4023
+ extentOffset: nextExtent.offset,
4024
+ );
4025
+ } else {
4026
+ if (_value.selection.extentOffset <= 0 ) {
4027
+ return ;
4028
+ }
4029
+ final Offset nextExtentOffset =
4030
+ Offset (extentRect.left, extentRect.top + increment);
4031
+ final TextPosition nextExtent = nextExtentOffset.dy + position.pixels <= 0
4032
+ ? const TextPosition (offset: 0 )
4033
+ : renderEditable.getPositionForPoint (
4034
+ renderEditable.localToGlobal (nextExtentOffset),
4035
+ );
4036
+ nextSelection = _value.selection.copyWith (
4037
+ extentOffset: nextExtent.offset,
4038
+ );
4039
+ }
4040
+
4041
+ bringIntoView (nextSelection.extent);
4042
+ userUpdateTextEditingValue (
4043
+ _value.copyWith (selection: nextSelection),
4044
+ SelectionChangedCause .keyboard,
4045
+ );
4046
+ }
4047
+
3956
4048
void _updateSelection (UpdateSelectionIntent intent) {
3957
4049
bringIntoView (intent.newSelection.extent);
3958
4050
userUpdateTextEditingValue (
@@ -4058,6 +4150,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
4058
4150
4059
4151
// Extend/Move Selection
4060
4152
ExtendSelectionByCharacterIntent : _makeOverridable (_UpdateTextSelectionAction <ExtendSelectionByCharacterIntent >(this , false , _characterBoundary)),
4153
+ ExtendSelectionByPageIntent : _makeOverridable (CallbackAction <ExtendSelectionByPageIntent >(onInvoke: _extendSelectionByPage)),
4061
4154
ExtendSelectionToNextWordBoundaryIntent : _makeOverridable (_UpdateTextSelectionAction <ExtendSelectionToNextWordBoundaryIntent >(this , true , _nextWordBoundary)),
4062
4155
ExtendSelectionToLineBreakIntent : _makeOverridable (_UpdateTextSelectionAction <ExtendSelectionToLineBreakIntent >(this , true , _linebreak)),
4063
4156
ExpandSelectionToLineBreakIntent : _makeOverridable (CallbackAction <ExpandSelectionToLineBreakIntent >(onInvoke: _expandSelectionToLinebreak)),
@@ -4067,6 +4160,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
4067
4160
ExtendSelectionToDocumentBoundaryIntent : _makeOverridable (_UpdateTextSelectionAction <ExtendSelectionToDocumentBoundaryIntent >(this , true , _documentBoundary)),
4068
4161
ExtendSelectionToNextWordBoundaryOrCaretLocationIntent : _makeOverridable (_ExtendSelectionOrCaretPositionAction (this , _nextWordBoundary)),
4069
4162
ScrollToDocumentBoundaryIntent : _makeOverridable (CallbackAction <ScrollToDocumentBoundaryIntent >(onInvoke: _scrollToDocumentBoundary)),
4163
+ ScrollIntent : CallbackAction <ScrollIntent >(onInvoke: _scroll),
4070
4164
4071
4165
// Copy Paste
4072
4166
SelectAllTextIntent : _makeOverridable (_SelectAllAction (this )),
@@ -4099,6 +4193,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
4099
4193
includeSemantics: false ,
4100
4194
debugLabel: kReleaseMode ? null : 'EditableText' ,
4101
4195
child: Scrollable (
4196
+ key: _scrollableKey,
4102
4197
excludeFromSemantics: true ,
4103
4198
axisDirection: _isMultiline ? AxisDirection .down : AxisDirection .right,
4104
4199
controller: _scrollController,
0 commit comments