diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index bda6cc5f8d..c33cbaeee8 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -2089,6 +2089,12 @@ class EditableTextState extends State with AutomaticKeepAliveClien )); } } + + // To keep the cursor from blinking while it moves, restart the timer here. + if (_cursorTimer != null) { + _stopCursorTimer(resetCharTicks: false); + _startCursorTimer(); + } } bool _textChangedSinceLastCaretUpdate = false; diff --git a/packages/flutter/test/widgets/editable_text_cursor_test.dart b/packages/flutter/test/widgets/editable_text_cursor_test.dart index 63ba5b5ab0..feae7aecb0 100644 --- a/packages/flutter/test/widgets/editable_text_cursor_test.dart +++ b/packages/flutter/test/widgets/editable_text_cursor_test.dart @@ -323,6 +323,81 @@ void main() { EditableText.debugDeterministicCursor = false; }); + testWidgets('Cursor animation restarts when it is moved using keys on desktop', (WidgetTester tester) async { + const String testText = 'Some text long enough to move the cursor around'; + final TextEditingController controller = TextEditingController(text: testText); + final Widget widget = MaterialApp( + home: EditableText( + controller: controller, + focusNode: FocusNode(), + style: const TextStyle(fontSize: 20.0), + maxLines: 1, + cursorColor: Colors.blue, + backgroundCursorColor: Colors.grey, + cursorOpacityAnimates: false, + selectionControls: materialTextSelectionControls, + keyboardType: TextInputType.text, + textAlign: TextAlign.left, + ), + ); + await tester.pumpWidget(widget); + + await tester.tap(find.byType(EditableText)); + await tester.pump(); + + final EditableTextState editableTextState = tester.firstState(find.byType(EditableText)); + final RenderEditable renderEditable = editableTextState.renderEditable; + + await tester.pump(); + expect(renderEditable.cursorColor!.alpha, 255); + expect(renderEditable, paints..rect(color: const Color(0xff2196f3))); + + // Android cursor goes from exactly on to exactly off on the 500ms dot. + await tester.pump(const Duration(milliseconds: 499)); + expect(renderEditable.cursorColor!.alpha, 255); + expect(renderEditable, paints..rect(color: const Color(0xff2196f3))); + + await tester.sendKeyDownEvent(LogicalKeyboardKey.arrowLeft); + await tester.pump(); + await tester.sendKeyUpEvent(LogicalKeyboardKey.arrowLeft); + + await tester.pump(); + expect(renderEditable.cursorColor!.alpha, 255); + expect(renderEditable, paints..rect(color: const Color(0xff2196f3))); + + await tester.pump(const Duration(milliseconds: 200)); + expect(renderEditable.cursorColor!.alpha, 255); + expect(renderEditable, paints..rect(color: const Color(0xff2196f3))); + + await tester.pump(const Duration(milliseconds: 299)); + expect(renderEditable.cursorColor!.alpha, 255); + expect(renderEditable, paints..rect(color: const Color(0xff2196f3))); + + await tester.sendKeyDownEvent(LogicalKeyboardKey.arrowRight); + await tester.pump(); + await tester.sendKeyUpEvent(LogicalKeyboardKey.arrowRight); + await tester.pump(); + await tester.sendKeyDownEvent(LogicalKeyboardKey.arrowRight); + await tester.pump(); + await tester.sendKeyUpEvent(LogicalKeyboardKey.arrowRight); + + await tester.pump(); + expect(renderEditable.cursorColor!.alpha, 255); + expect(renderEditable, paints..rect(color: const Color(0xff2196f3))); + + await tester.pump(const Duration(milliseconds: 200)); + expect(renderEditable.cursorColor!.alpha, 255); + expect(renderEditable, paints..rect(color: const Color(0xff2196f3))); + + await tester.pump(const Duration(milliseconds: 299)); + expect(renderEditable.cursorColor!.alpha, 255); + expect(renderEditable, paints..rect(color: const Color(0xff2196f3))); + + await tester.pump(const Duration(milliseconds: 1)); + expect(renderEditable.cursorColor!.alpha, 0); + expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); + }, variant: const TargetPlatformVariant({ TargetPlatform.macOS })); + testWidgets('Cursor does not show when showCursor set to false', (WidgetTester tester) async { const Widget widget = MaterialApp( home: Material(