diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index 41a13c6f38..ae2a1e0b62 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -1793,13 +1793,12 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, final double caretX = clampDouble(caretRect.left, 0, math.max(scrollableWidth - _caretMargin, 0)); caretRect = Offset(caretX, caretRect.top) & caretRect.size; - final double caretHeight = cursorHeight; + final double fullHeight = _textPainter.getFullHeightForCaret(caretPosition, caretPrototype); switch (defaultTargetPlatform) { case TargetPlatform.iOS: case TargetPlatform.macOS: - final double fullHeight = _textPainter.getFullHeightForCaret(caretPosition, caretPrototype); - final double heightDiff = fullHeight - caretRect.height; // Center the caret vertically along the text. + final double heightDiff = fullHeight - caretRect.height; caretRect = Rect.fromLTWH( caretRect.left, caretRect.top + heightDiff / 2, @@ -1812,10 +1811,13 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, case TargetPlatform.windows: // Override the height to take the full height of the glyph at the TextPosition // when not on iOS. iOS has special handling that creates a taller caret. - // TODO(garyq): See the TODO for _computeCaretPrototype(). + // TODO(garyq): see https://github.com/flutter/flutter/issues/120836. + final double caretHeight = cursorHeight; + // Center the caret vertically along the text. + final double heightDiff = fullHeight - caretHeight; caretRect = Rect.fromLTWH( caretRect.left, - caretRect.top - _kCaretHeightOffset, + caretRect.top - _kCaretHeightOffset + heightDiff / 2, caretRect.width, caretHeight, ); diff --git a/packages/flutter/test/widgets/editable_text_cursor_test.dart b/packages/flutter/test/widgets/editable_text_cursor_test.dart index 59e3a4e62f..c4b34703e8 100644 --- a/packages/flutter/test/widgets/editable_text_cursor_test.dart +++ b/packages/flutter/test/widgets/editable_text_cursor_test.dart @@ -1236,7 +1236,7 @@ void main() { backgroundCursorColor: Colors.grey, controller: controller, focusNode: focusNode, - style: const TextStyle(), + style: const TextStyle(fontSize: 17), textAlign: TextAlign.center, keyboardType: TextInputType.text, cursorColor: cursorColor, @@ -1267,6 +1267,96 @@ void main() { skip: isBrowser && !isCanvasKit, // https://github.com/flutter/flutter/issues/56308 ); + testWidgets( + 'Caret with a cursorHeight smaller than font size is vertically centered on non-Apple platforms', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/143480. + final TextEditingController controller = TextEditingController.fromValue( + const TextEditingValue(selection: TextSelection.collapsed(offset: 0)), + ); + addTearDown(controller.dispose); + + const double cursorHeight = 12.0; + const double cursorWidth = 4.0; + const double fontSize = 16.0; + + final Widget widget = EditableText( + autofocus: true, + backgroundCursorColor: Colors.grey, + controller: controller, + focusNode: focusNode, + style: const TextStyle(fontSize: fontSize), + keyboardType: TextInputType.text, + cursorColor: cursorColor, + cursorHeight: cursorHeight, + cursorWidth: cursorWidth, + ); + await tester.pumpWidget(MaterialApp(home: widget)); + + final EditableTextState editableTextState = tester.firstState(find.byWidget(widget)); + final RenderEditable renderEditable = editableTextState.renderEditable; + + // The caretRect is vertically centered. + const Rect caretRect = Rect.fromLTWH( + 0.0, + (fontSize - cursorHeight) / 2, + cursorWidth, + cursorHeight, + ); + expect( + renderEditable, + paints..rect(color: cursorColor, rect: caretRect), + ); + }, + variant: TargetPlatformVariant.all(excluding: {TargetPlatform.macOS, TargetPlatform.iOS}), + skip: isBrowser && !isCanvasKit, // https://github.com/flutter/flutter/issues/56308 + ); + + testWidgets( + 'Caret with a cursorHeight bigger than font size is vertically centered on non-Apple platforms', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/143480. + final TextEditingController controller = TextEditingController.fromValue( + const TextEditingValue(selection: TextSelection.collapsed(offset: 0)), + ); + addTearDown(controller.dispose); + + const double cursorHeight = 24.0; + const double cursorWidth = 4.0; + const double fontSize = 16.0; + + final Widget widget = EditableText( + autofocus: true, + backgroundCursorColor: Colors.grey, + controller: controller, + focusNode: focusNode, + style: const TextStyle(fontSize: fontSize), + keyboardType: TextInputType.text, + cursorColor: cursorColor, + cursorHeight: cursorHeight, + cursorWidth: cursorWidth, + ); + await tester.pumpWidget(MaterialApp(home: widget)); + + final EditableTextState editableTextState = tester.firstState(find.byWidget(widget)); + final RenderEditable renderEditable = editableTextState.renderEditable; + + // The caretRect is vertically centered. + const Rect caretRect = Rect.fromLTWH( + 0.0, + (fontSize - cursorHeight) / 2, + cursorWidth, + cursorHeight, + ); + expect( + renderEditable, + paints..rect(color: cursorColor, rect: caretRect), + ); + }, + variant: TargetPlatformVariant.all(excluding: {TargetPlatform.macOS, TargetPlatform.iOS}), + skip: isBrowser && !isCanvasKit, // https://github.com/flutter/flutter/issues/56308 + ); + testWidgets('getLocalRectForCaret reports the real caret Rect', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; addTearDown(() { EditableText.debugDeterministicCursor = false; });