@@ -30,6 +30,13 @@ const EdgeInsets _kFloatingCursorSizeIncrease = EdgeInsets.symmetric(horizontal:
3030// The corner radius of the floating cursor in pixels.
3131const Radius _kFloatingCursorRadius = Radius .circular (1.0 );
3232
33+ // This constant represents the shortest squared distance required between the floating cursor
34+ // and the regular cursor when both are present in the text field.
35+ // If the squared distance between the two cursors is less than this value,
36+ // it's not necessary to display both cursors at the same time.
37+ // This behavior is consistent with the one observed in iOS UITextField.
38+ const double _kShortestDistanceSquaredWithFloatingAndRegularCursors = 15.0 * 15.0 ;
39+
3340/// Represents the coordinates of the point in a selection, and the text
3441/// direction at that point, relative to top left of the [RenderEditable] that
3542/// holds the selection.
@@ -2360,19 +2367,35 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
23602367 // difference in the rendering position and the raw offset value.
23612368 Offset _relativeOrigin = Offset .zero;
23622369 Offset ? _previousOffset;
2370+ bool _shouldResetOrigin = true ;
23632371 bool _resetOriginOnLeft = false ;
23642372 bool _resetOriginOnRight = false ;
23652373 bool _resetOriginOnTop = false ;
23662374 bool _resetOriginOnBottom = false ;
23672375 double ? _resetFloatingCursorAnimationValue;
23682376
2377+ static Offset _calculateAdjustedCursorOffset (Offset offset, Rect boundingRects) {
2378+ final double adjustedX = clampDouble (offset.dx, boundingRects.left, boundingRects.right);
2379+ final double adjustedY = clampDouble (offset.dy, boundingRects.top, boundingRects.bottom);
2380+ return Offset (adjustedX, adjustedY);
2381+ }
2382+
23692383 /// Returns the position within the text field closest to the raw cursor offset.
2370- Offset calculateBoundedFloatingCursorOffset (Offset rawCursorOffset) {
2384+ Offset calculateBoundedFloatingCursorOffset (Offset rawCursorOffset, { bool ? shouldResetOrigin} ) {
23712385 Offset deltaPosition = Offset .zero;
23722386 final double topBound = - floatingCursorAddedMargin.top;
2373- final double bottomBound = _textPainter.height - preferredLineHeight + floatingCursorAddedMargin.bottom;
2387+ final double bottomBound = math. min (size.height, _textPainter.height) - preferredLineHeight + floatingCursorAddedMargin.bottom;
23742388 final double leftBound = - floatingCursorAddedMargin.left;
2375- final double rightBound = _textPainter.width + floatingCursorAddedMargin.right;
2389+ final double rightBound = math.min (size.width, _textPainter.width) + floatingCursorAddedMargin.right;
2390+ final Rect boundingRects = Rect .fromLTRB (leftBound, topBound, rightBound, bottomBound);
2391+
2392+ if (shouldResetOrigin != null ) {
2393+ _shouldResetOrigin = shouldResetOrigin;
2394+ }
2395+
2396+ if (! _shouldResetOrigin) {
2397+ return _calculateAdjustedCursorOffset (rawCursorOffset, boundingRects);
2398+ }
23762399
23772400 if (_previousOffset != null ) {
23782401 deltaPosition = rawCursorOffset - _previousOffset! ;
@@ -2381,34 +2404,32 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
23812404 // If the raw cursor offset has gone off an edge, we want to reset the relative
23822405 // origin of the dragging when the user drags back into the field.
23832406 if (_resetOriginOnLeft && deltaPosition.dx > 0 ) {
2384- _relativeOrigin = Offset (rawCursorOffset.dx - leftBound , _relativeOrigin.dy);
2407+ _relativeOrigin = Offset (rawCursorOffset.dx - boundingRects.left , _relativeOrigin.dy);
23852408 _resetOriginOnLeft = false ;
23862409 } else if (_resetOriginOnRight && deltaPosition.dx < 0 ) {
2387- _relativeOrigin = Offset (rawCursorOffset.dx - rightBound , _relativeOrigin.dy);
2410+ _relativeOrigin = Offset (rawCursorOffset.dx - boundingRects.right , _relativeOrigin.dy);
23882411 _resetOriginOnRight = false ;
23892412 }
23902413 if (_resetOriginOnTop && deltaPosition.dy > 0 ) {
2391- _relativeOrigin = Offset (_relativeOrigin.dx, rawCursorOffset.dy - topBound );
2414+ _relativeOrigin = Offset (_relativeOrigin.dx, rawCursorOffset.dy - boundingRects.top );
23922415 _resetOriginOnTop = false ;
23932416 } else if (_resetOriginOnBottom && deltaPosition.dy < 0 ) {
2394- _relativeOrigin = Offset (_relativeOrigin.dx, rawCursorOffset.dy - bottomBound );
2417+ _relativeOrigin = Offset (_relativeOrigin.dx, rawCursorOffset.dy - boundingRects.bottom );
23952418 _resetOriginOnBottom = false ;
23962419 }
23972420
23982421 final double currentX = rawCursorOffset.dx - _relativeOrigin.dx;
23992422 final double currentY = rawCursorOffset.dy - _relativeOrigin.dy;
2400- final double adjustedX = math.min (math.max (currentX, leftBound), rightBound);
2401- final double adjustedY = math.min (math.max (currentY, topBound), bottomBound);
2402- final Offset adjustedOffset = Offset (adjustedX, adjustedY);
2423+ final Offset adjustedOffset = _calculateAdjustedCursorOffset (Offset (currentX, currentY), boundingRects);
24032424
2404- if (currentX < leftBound && deltaPosition.dx < 0 ) {
2425+ if (currentX < boundingRects.left && deltaPosition.dx < 0 ) {
24052426 _resetOriginOnLeft = true ;
2406- } else if (currentX > rightBound && deltaPosition.dx > 0 ) {
2427+ } else if (currentX > boundingRects.right && deltaPosition.dx > 0 ) {
24072428 _resetOriginOnRight = true ;
24082429 }
2409- if (currentY < topBound && deltaPosition.dy < 0 ) {
2430+ if (currentY < boundingRects.top && deltaPosition.dy < 0 ) {
24102431 _resetOriginOnTop = true ;
2411- } else if (currentY > bottomBound && deltaPosition.dy > 0 ) {
2432+ } else if (currentY > boundingRects.bottom && deltaPosition.dy > 0 ) {
24122433 _resetOriginOnBottom = true ;
24132434 }
24142435
@@ -2420,9 +2441,10 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
24202441 /// Sets the screen position of the floating cursor and the text position
24212442 /// closest to the cursor.
24222443 void setFloatingCursor (FloatingCursorDragState state, Offset boundedOffset, TextPosition lastTextPosition, { double ? resetLerpValue }) {
2423- if (state == FloatingCursorDragState .Start ) {
2444+ if (state == FloatingCursorDragState .End ) {
24242445 _relativeOrigin = Offset .zero;
24252446 _previousOffset = null ;
2447+ _shouldResetOrigin = true ;
24262448 _resetOriginOnBottom = false ;
24272449 _resetOriginOnTop = false ;
24282450 _resetOriginOnRight = false ;
@@ -2898,6 +2920,12 @@ class _CaretPainter extends RenderEditablePainter {
28982920 void paintRegularCursor (Canvas canvas, RenderEditable renderEditable, Color caretColor, TextPosition textPosition) {
28992921 final Rect integralRect = renderEditable.getLocalRectForCaret (textPosition);
29002922 if (shouldPaint) {
2923+ if (floatingCursorRect != null ) {
2924+ final double distanceSquared = (floatingCursorRect! .center - integralRect.center).distanceSquared;
2925+ if (distanceSquared < _kShortestDistanceSquaredWithFloatingAndRegularCursors) {
2926+ return ;
2927+ }
2928+ }
29012929 final Radius ? radius = cursorRadius;
29022930 caretPaint.color = caretColor;
29032931 if (radius == null ) {
0 commit comments