Use TextPainter.preferredLineHeight to estimate line height for Cupertino selection handles (#12833)
Fixes https://github.com/flutter/flutter/issues/12046
This commit is contained in:
parent
89405002bc
commit
b865b0eb2f
@ -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);
|
||||
@ -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
|
||||
@ -456,12 +456,13 @@ 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;
|
||||
@ -469,10 +470,10 @@ class RenderEditable extends RenderBox {
|
||||
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
|
||||
@ -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
|
||||
|
@ -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(
|
||||
@ -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,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user