diff --git a/packages/flutter/lib/src/material/text_selection.dart b/packages/flutter/lib/src/material/text_selection.dart index eba02b4903..5f0ee5fda9 100644 --- a/packages/flutter/lib/src/material/text_selection.dart +++ b/packages/flutter/lib/src/material/text_selection.dart @@ -104,8 +104,7 @@ class _TextSelectionToolbarLayout extends SingleChildLayoutDelegate { } } -/// Draws a single text selection handle. The [type] determines where the handle -/// points (e.g. the [left] handle points up and to the right). +/// Draws a single text selection handle which points up and to the left. class _TextSelectionHandlePainter extends CustomPainter { _TextSelectionHandlePainter({ this.color }); diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index 551d379396..663d3d5efe 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -921,7 +921,11 @@ class RenderEditable extends RenderBox { return null; } - bool _hasVisualOverflow = false; + double _maxScrollExtent = 0; + + // We need to check the paint offset here because during animation, the start of + // the text may position outside the visible region even when the text fits. + bool get _hasVisualOverflow => _maxScrollExtent > 0 || _paintOffset != Offset.zero; /// Returns the local coordinates of the endpoints of the given selection. /// @@ -1146,8 +1150,7 @@ class RenderEditable extends RenderBox { final Size textPainterSize = _textPainter.size; size = Size(constraints.maxWidth, constraints.constrainHeight(_preferredHeight(constraints.maxWidth))); final Size contentSize = Size(textPainterSize.width + _kCaretGap + cursorWidth, textPainterSize.height); - final double _maxScrollExtent = _getMaxScrollExtent(contentSize); - _hasVisualOverflow = _maxScrollExtent > 0.0; + _maxScrollExtent = _getMaxScrollExtent(contentSize); offset.applyViewportDimension(_viewportExtent); offset.applyContentDimensions(0.0, _maxScrollExtent); } diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart index 53b4ff05a4..c682d7b563 100644 --- a/packages/flutter/test/rendering/editable_test.dart +++ b/packages/flutter/test/rendering/editable_test.dart @@ -6,6 +6,9 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/services.dart'; +import '../rendering/mock_canvas.dart'; +import '../rendering/recording_canvas.dart'; + class FakeEditableTextState extends TextSelectionDelegate { @override TextEditingValue get textEditingValue { return const TextEditingValue(); } @@ -65,4 +68,27 @@ void main() { ), ); }); + + // Test that clipping will be used even when the text fits within the visible + // region if the start position of the text is offset (e.g. during scrolling + // animation). + test('correct clipping', () { + final TextSelectionDelegate delegate = FakeEditableTextState(); + final RenderEditable editable = RenderEditable( + text: const TextSpan( + style: TextStyle(height: 1.0, fontSize: 10.0, fontFamily: 'Ahem'), + text: 'A', + ), + textAlign: TextAlign.start, + textDirection: TextDirection.ltr, + locale: const Locale('en', 'US'), + offset: ViewportOffset.fixed(10.0), + textSelectionDelegate: delegate, + ); + editable.layout(BoxConstraints.loose(const Size(1000.0, 1000.0))); + expect( + (Canvas canvas) => editable.paint(TestRecordingPaintingContext(canvas), Offset.zero), + paints..clipRect(rect: Rect.fromLTRB(0.0, 0.0, 1000.0, 10.0)) + ); + }); }