Skip to content

Commit

Permalink
Use TextPainter.preferredLineHeight to estimate line height for Cuper…
Browse files Browse the repository at this point in the history
…tino selection handles (#12833)

Fixes #12046
  • Loading branch information
jason-simmons committed Nov 3, 2017
1 parent 8940500 commit b865b0e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 10 deletions.
17 changes: 9 additions & 8 deletions packages/flutter/lib/src/rendering/editable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ class RenderEditable extends RenderBox {
if (selection.isCollapsed) {
// TODO(mpcomplete): This doesn't work well at an RTL/LTR boundary.
final Offset caretOffset = _textPainter.getOffsetForCaret(selection.extent, _caretPrototype);
final Offset start = new Offset(0.0, _preferredLineHeight) + caretOffset + paintOffset;
final Offset start = new Offset(0.0, preferredLineHeight) + caretOffset + paintOffset;
return <TextSelectionPoint>[new TextSelectionPoint(start, null)];
} else {
final List<ui.TextBox> boxes = _textPainter.getBoxesForSelection(selection);
Expand Down Expand Up @@ -441,7 +441,7 @@ class RenderEditable extends RenderBox {
_layoutText(constraints.maxWidth);
final Offset caretOffset = _textPainter.getOffsetForCaret(caretPosition, _caretPrototype);
// This rect is the same as _caretPrototype but without the vertical padding.
return new Rect.fromLTWH(0.0, 0.0, _kCaretWidth, _preferredLineHeight).shift(caretOffset + _paintOffset);
return new Rect.fromLTWH(0.0, 0.0, _kCaretWidth, preferredLineHeight).shift(caretOffset + _paintOffset);
}

@override
Expand All @@ -456,23 +456,24 @@ class RenderEditable extends RenderBox {
return _textPainter.maxIntrinsicWidth;
}

// This does not required the layout to be updated.
double get _preferredLineHeight => _textPainter.preferredLineHeight;
/// An estimate of the height of a line in the text. See [TextPainter.preferredLineHeight].
/// This does not required the layout to be updated.
double get preferredLineHeight => _textPainter.preferredLineHeight;

double _preferredHeight(double width) {
if (maxLines != null)
return _preferredLineHeight * maxLines;
return preferredLineHeight * maxLines;
if (width == double.INFINITY) {
final String text = _textPainter.text.toPlainText();
int lines = 1;
for (int index = 0; index < text.length; index += 1) {
if (text.codeUnitAt(index) == 0x0A) // count explicit line breaks
lines += 1;
}
return _preferredLineHeight * lines;
return preferredLineHeight * lines;
}
_layoutText(width);
return math.max(_preferredLineHeight, _textPainter.height);
return math.max(preferredLineHeight, _textPainter.height);
}

@override
Expand Down Expand Up @@ -558,7 +559,7 @@ class RenderEditable extends RenderBox {
@override
void performLayout() {
_layoutText(constraints.maxWidth);
_caretPrototype = new Rect.fromLTWH(0.0, _kCaretHeightOffset, _kCaretWidth, _preferredLineHeight - 2.0 * _kCaretHeightOffset);
_caretPrototype = new Rect.fromLTWH(0.0, _kCaretHeightOffset, _kCaretWidth, preferredLineHeight - 2.0 * _kCaretHeightOffset);
_selectionRects = null;
// We grab _textPainter.size here because assigning to `size` on the next
// line will trigger us to validate our intrinsic sizes, which will change
Expand Down
4 changes: 2 additions & 2 deletions packages/flutter/lib/src/widgets/text_selection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ class TextSelectionOverlay implements TextSelectionDelegate {
(endpoints.length == 1) ?
endpoints[0].point.dx :
(endpoints[0].point.dx + endpoints[1].point.dx) / 2.0,
endpoints[0].point.dy - renderObject.size.height,
endpoints[0].point.dy - renderObject.preferredLineHeight,
);

final Rect editingRegion = new Rect.fromPoints(
Expand Down Expand Up @@ -509,7 +509,7 @@ class _TextSelectionHandleOverlayState extends State<_TextSelectionHandleOverlay
child: widget.selectionControls.buildHandle(
context,
type,
widget.renderObject.size.height / widget.renderObject.maxLines,
widget.renderObject.preferredLineHeight,
),
),
],
Expand Down
26 changes: 26 additions & 0 deletions packages/flutter/test/material/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1664,4 +1664,30 @@ void main() {

expect(semantics, includesNodeWith(flags: <SemanticsFlags>[SemanticsFlags.isTextField]));
});

testWidgets('Caret works when maxLines is null', (WidgetTester tester) async {
final TextEditingController controller = new TextEditingController();

await tester.pumpWidget(
overlay(
child: new TextField(
controller: controller,
maxLines: null,
),
)
);

final String testValue = 'x';
await tester.enterText(find.byType(TextField), testValue);
await skipPastScrollingAnimation(tester);
expect(controller.selection.baseOffset, -1);

// Tap the selection handle to bring up the "paste / select all" menu.
await tester.tapAt(textOffsetToPosition(tester, 0));
await tester.pump();
await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is

// Confirm that the selection was updated.
expect(controller.selection.baseOffset, 0);
});
}

0 comments on commit b865b0e

Please sign in to comment.