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) {
|
if (selection.isCollapsed) {
|
||||||
// TODO(mpcomplete): This doesn't work well at an RTL/LTR boundary.
|
// TODO(mpcomplete): This doesn't work well at an RTL/LTR boundary.
|
||||||
final Offset caretOffset = _textPainter.getOffsetForCaret(selection.extent, _caretPrototype);
|
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)];
|
return <TextSelectionPoint>[new TextSelectionPoint(start, null)];
|
||||||
} else {
|
} else {
|
||||||
final List<ui.TextBox> boxes = _textPainter.getBoxesForSelection(selection);
|
final List<ui.TextBox> boxes = _textPainter.getBoxesForSelection(selection);
|
||||||
@ -441,7 +441,7 @@ class RenderEditable extends RenderBox {
|
|||||||
_layoutText(constraints.maxWidth);
|
_layoutText(constraints.maxWidth);
|
||||||
final Offset caretOffset = _textPainter.getOffsetForCaret(caretPosition, _caretPrototype);
|
final Offset caretOffset = _textPainter.getOffsetForCaret(caretPosition, _caretPrototype);
|
||||||
// This rect is the same as _caretPrototype but without the vertical padding.
|
// 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
|
@override
|
||||||
@ -456,12 +456,13 @@ class RenderEditable extends RenderBox {
|
|||||||
return _textPainter.maxIntrinsicWidth;
|
return _textPainter.maxIntrinsicWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This does not required the layout to be updated.
|
/// An estimate of the height of a line in the text. See [TextPainter.preferredLineHeight].
|
||||||
double get _preferredLineHeight => _textPainter.preferredLineHeight;
|
/// This does not required the layout to be updated.
|
||||||
|
double get preferredLineHeight => _textPainter.preferredLineHeight;
|
||||||
|
|
||||||
double _preferredHeight(double width) {
|
double _preferredHeight(double width) {
|
||||||
if (maxLines != null)
|
if (maxLines != null)
|
||||||
return _preferredLineHeight * maxLines;
|
return preferredLineHeight * maxLines;
|
||||||
if (width == double.INFINITY) {
|
if (width == double.INFINITY) {
|
||||||
final String text = _textPainter.text.toPlainText();
|
final String text = _textPainter.text.toPlainText();
|
||||||
int lines = 1;
|
int lines = 1;
|
||||||
@ -469,10 +470,10 @@ class RenderEditable extends RenderBox {
|
|||||||
if (text.codeUnitAt(index) == 0x0A) // count explicit line breaks
|
if (text.codeUnitAt(index) == 0x0A) // count explicit line breaks
|
||||||
lines += 1;
|
lines += 1;
|
||||||
}
|
}
|
||||||
return _preferredLineHeight * lines;
|
return preferredLineHeight * lines;
|
||||||
}
|
}
|
||||||
_layoutText(width);
|
_layoutText(width);
|
||||||
return math.max(_preferredLineHeight, _textPainter.height);
|
return math.max(preferredLineHeight, _textPainter.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -558,7 +559,7 @@ class RenderEditable extends RenderBox {
|
|||||||
@override
|
@override
|
||||||
void performLayout() {
|
void performLayout() {
|
||||||
_layoutText(constraints.maxWidth);
|
_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;
|
_selectionRects = null;
|
||||||
// We grab _textPainter.size here because assigning to `size` on the next
|
// We grab _textPainter.size here because assigning to `size` on the next
|
||||||
// line will trigger us to validate our intrinsic sizes, which will change
|
// line will trigger us to validate our intrinsic sizes, which will change
|
||||||
|
@ -344,7 +344,7 @@ class TextSelectionOverlay implements TextSelectionDelegate {
|
|||||||
(endpoints.length == 1) ?
|
(endpoints.length == 1) ?
|
||||||
endpoints[0].point.dx :
|
endpoints[0].point.dx :
|
||||||
(endpoints[0].point.dx + endpoints[1].point.dx) / 2.0,
|
(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(
|
final Rect editingRegion = new Rect.fromPoints(
|
||||||
@ -509,7 +509,7 @@ class _TextSelectionHandleOverlayState extends State<_TextSelectionHandleOverlay
|
|||||||
child: widget.selectionControls.buildHandle(
|
child: widget.selectionControls.buildHandle(
|
||||||
context,
|
context,
|
||||||
type,
|
type,
|
||||||
widget.renderObject.size.height / widget.renderObject.maxLines,
|
widget.renderObject.preferredLineHeight,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1664,4 +1664,30 @@ void main() {
|
|||||||
|
|
||||||
expect(semantics, includesNodeWith(flags: <SemanticsFlags>[SemanticsFlags.isTextField]));
|
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