diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index b2ccef4320b6538cf62ee067f284adeb89d20282..5fd0c211a0a98e62df95f5a1526c12413a8841b2 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -1296,6 +1296,7 @@ class TextInputConnection { _id = _nextId++; Size? _cachedSize; + Rect? _cachedPosition; Matrix4? _cachedTransform; Rect? _cachedRect; Rect? _cachedCaretRect; @@ -1334,6 +1335,13 @@ class TextInputConnection { TextInput._instance._show(); } + void setCursorPotion(Rect rect) { + if (rect != _cachedPosition) { + _cachedPosition = rect; + TextInput._instance._setCursorPotion(rect); + } + } + /// Requests the system autofill UI to appear. /// /// Currently only works on Android. Other platforms do not respond to this @@ -1968,6 +1976,12 @@ class TextInput { } } + void _setCursorPotion(Rect position) { + for (final TextInputControl control in _inputControls) { + control.setCursorPotion(position); + } + } + void _setEditableSizeAndTransform(Size editableBoxSize, Matrix4 transform) { for (final TextInputControl control in _inputControls) { control.setEditableSizeAndTransform(editableBoxSize, transform); @@ -2157,6 +2171,10 @@ mixin TextInputControl { /// /// This method is called when the input control should hide. void hide() {} + /// Requests that the text input control is hidden. + /// + /// This method is called when the input control should hide. + void setCursorPotion(Rect position) {} /// Informs the text input control about input configuration changes. /// @@ -2316,6 +2334,19 @@ class _PlatformTextInputControl with TextInputControl { ); } + @override + void setCursorPotion(Rect position) { + _channel.invokeMethod( + 'TextInput.setCursorPotion', + [{ + 'left': position.left, + 'top': position.top, + 'width': position.width, + 'height': position.height, + }], + ); + } + @override void setSelectionRects(List selectionRects) { _channel.invokeMethod( diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 0e5dc987e86dc800a0981fc90455f10de5c70b1a..c2fb05fdbbb7cffc0b53b60810814ded89ad401f 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:math' as math; +import 'dart:ui'; import 'dart:ui' as ui hide TextStyle; import 'package:characters/characters.dart' show CharacterRange, StringCharacters; @@ -3379,6 +3380,9 @@ class EditableTextState extends State with AutomaticKeepAliveClien if (!_tickersEnabled) { return; } + + _setCursorPotion(); + _cursorTimer?.cancel(); _cursorBlinkOpacityController.value = 1.0; if (EditableText.debugDeterministicCursor) { @@ -3391,6 +3395,23 @@ class EditableTextState extends State with AutomaticKeepAliveClien } } + void _setCursorPotion() { + var box = _editableKey.currentContext!.findRenderObject() as RenderBox; + final Offset position = box.localToGlobal(Offset.zero); + + final TextPosition currentTextPosition = TextPosition(offset: renderEditable.selection!.baseOffset); + Rect? startPosition = renderEditable.getLocalRectForCaret(currentTextPosition); + + Offset? lastOffset = startPosition!.center + position; + + final width = window.physicalSize.width; + final height = window.physicalSize.height; + + Rect? newRect = Rect.fromPoints(lastOffset * window.devicePixelRatio, Offset(width, height)); + + _textInputConnection!.setCursorPotion(newRect); + } + void _onCursorTick() { if (_obscureShowCharTicksPending > 0) { _obscureShowCharTicksPending = WidgetsBinding.instance.platformDispatcher.brieflyShowPassword