Skip to content

Commit 51a6dce

Browse files
committed
Fix an issue that Dragging the iOS text selection handles is jumpy (flutter#106703)
1 parent efd54a2 commit 51a6dce

File tree

8 files changed

+73
-2
lines changed

8 files changed

+73
-2
lines changed

packages/flutter/lib/src/cupertino/desktop_text_selection.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ class _CupertinoDesktopTextSelectionControls extends TextSelectionControls {
4040
return Size.zero;
4141
}
4242

43+
/// Returns the offset from text selection handle to actual location in text line.
44+
///
45+
/// Desktop has no text selection handles, return [Offset.zero].
46+
@override
47+
Offset getOffsetFromHandleToTextPosition(Size handleSize) {
48+
return Offset.zero;
49+
}
50+
4351
/// Builder for the Mac-style copy/paste text selection toolbar.
4452
@override
4553
Widget buildToolbar(

packages/flutter/lib/src/cupertino/text_selection.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,14 @@ class CupertinoTextSelectionControls extends TextSelectionControls {
202202
);
203203
}
204204

205+
/// Returns the offset from text selection handle to actual location in text line.
206+
///
207+
/// To Cupertino text selection style,handle overlaps the text line, return [Offset.zero].
208+
@override
209+
Offset getOffsetFromHandleToTextPosition(Size handleSize) {
210+
return Offset.zero;
211+
}
212+
205213
/// Builder for iOS-style copy/paste text selection toolbar.
206214
@override
207215
Widget buildToolbar(

packages/flutter/lib/src/material/desktop_text_selection.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ class _DesktopTextSelectionControls extends TextSelectionControls {
2626
return Size.zero;
2727
}
2828

29+
/// Returns the offset from text selection handle to actual location in text line.
30+
///
31+
/// Desktop has no text selection handles, return [Offset.zero].
32+
@override
33+
Offset getOffsetFromHandleToTextPosition(Size handleSize) {
34+
return Offset.zero;
35+
}
36+
2937
/// Builder for the Material-style desktop copy/paste text selection toolbar.
3038
@override
3139
Widget buildToolbar(

packages/flutter/lib/src/material/text_selection.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ class MaterialTextSelectionControls extends TextSelectionControls {
2626
@override
2727
Size getHandleSize(double textLineHeight) => const Size(_kHandleSize, _kHandleSize);
2828

29+
/// Returns the offset from text selection handle to actual location in text line.
30+
///
31+
/// To Material text selection style,handle is located below the text line.
32+
/// The OffsetX from selection handle to text line is 0.0, OffsetY is handle height;
33+
/// Return [Offset(0.0, -handleSize.height)]
34+
@override
35+
Offset getOffsetFromHandleToTextPosition(Size handleSize) {
36+
return Offset(0.0, -handleSize.height);
37+
}
38+
2939
/// Builder for material-style copy/paste text selection toolbar.
3040
@override
3141
Widget buildToolbar(

packages/flutter/lib/src/widgets/text_selection.dart

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,16 @@ abstract class TextSelectionControls {
275275
/// Returns the size of the selection handle.
276276
Size getHandleSize(double textLineHeight);
277277

278+
/// Returns the offset from text selection handle to actual location in text line.
279+
///
280+
/// To Material text selection, handle is located below the text line.
281+
/// To Cupertino text selection, handle overlaps the text line.
282+
/// To Desktop text selection, has no text selection handles.
283+
///
284+
/// For different relative position from selection handle to text line,
285+
/// return different offset for accurate text selection updates.
286+
Offset getOffsetFromHandleToTextPosition(Size handleSize);
287+
278288
/// Whether the current selection of the text field managed by the given
279289
/// `delegate` can be removed from the text field and placed into the
280290
/// [Clipboard].
@@ -617,7 +627,10 @@ class TextSelectionOverlay {
617627
renderObject.preferredLineHeight,
618628
);
619629

620-
_dragEndPosition = details.globalPosition + Offset(0.0, -handleSize.height);
630+
final Offset offsetFromHandleToTextPosition = selectionControls!
631+
.getOffsetFromHandleToTextPosition(handleSize);
632+
633+
_dragEndPosition = details.globalPosition + offsetFromHandleToTextPosition;
621634
final TextPosition position = renderObject.getPositionForPoint(_dragEndPosition);
622635

623636
_selectionOverlay.showMagnifier(MagnifierOverlayInfoBearer._fromRenderEditable(
@@ -692,7 +705,11 @@ class TextSelectionOverlay {
692705
final Size handleSize = selectionControls!.getHandleSize(
693706
renderObject.preferredLineHeight,
694707
);
695-
_dragStartPosition = details.globalPosition + Offset(0.0, -handleSize.height);
708+
709+
final Offset offsetFromHandleToTextPosition = selectionControls!
710+
.getOffsetFromHandleToTextPosition(handleSize);
711+
712+
_dragStartPosition = details.globalPosition + offsetFromHandleToTextPosition;
696713
final TextPosition position = renderObject.getPositionForPoint(_dragStartPosition);
697714

698715
_selectionOverlay.showMagnifier(MagnifierOverlayInfoBearer._fromRenderEditable(

packages/flutter/test/cupertino/text_field_test.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ class MockTextSelectionControls extends TextSelectionControls {
5959
Size getHandleSize(double textLineHeight) {
6060
throw UnimplementedError();
6161
}
62+
63+
@override
64+
Offset getOffsetFromHandleToTextPosition(Size handleSize) {
65+
throw UnimplementedError();
66+
}
6267
}
6368

6469
class PathBoundsMatcher extends Matcher {

packages/flutter/test/widgets/editable_text_test.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12755,6 +12755,11 @@ class MockTextSelectionControls extends Fake implements TextSelectionControls {
1275512755
return Offset.zero;
1275612756
}
1275712757

12758+
@override
12759+
Offset getOffsetFromHandleToTextPosition(Size handleSize) {
12760+
return Offset.zero;
12761+
}
12762+
1275812763
bool testCanCut = false;
1275912764
bool testCanCopy = false;
1276012765
bool testCanPaste = false;
@@ -12853,6 +12858,11 @@ class _CustomTextSelectionControls extends TextSelectionControls {
1285312858
return Size.zero;
1285412859
}
1285512860

12861+
@override
12862+
Offset getOffsetFromHandleToTextPosition(Size handleSize) {
12863+
return Offset.zero;
12864+
}
12865+
1285612866
@override
1285712867
Offset getHandleAnchor(TextSelectionHandleType type, double textLineHeight) {
1285812868
return Offset.zero;

packages/flutter/test/widgets/text_selection_test.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,11 @@ class TextSelectionControlsSpy extends TextSelectionControls {
14711471
Size getHandleSize(double textLineHeight) {
14721472
return Size(textLineHeight, textLineHeight);
14731473
}
1474+
1475+
@override
1476+
Offset getOffsetFromHandleToTextPosition(Size handleSize) {
1477+
return Offset.zero;
1478+
}
14741479
}
14751480

14761481
class FakeClipboardStatusNotifier extends ClipboardStatusNotifier {

0 commit comments

Comments
 (0)