Fix cursor outside of input width (#30525)
* Disallow cursor from appearing beyond the width of the input. * Test that verifies the cursor can't exceed the width of the input * Use constant from editable.dart to explain 1 pixel difference in test * Fix failing test that tested the case of overflowing spaces
This commit is contained in:
parent
5a6c140d0d
commit
ed91a3be49
@ -486,7 +486,7 @@ class TextPainter {
|
||||
|
||||
final double caretEnd = box.end;
|
||||
final double dx = box.direction == TextDirection.rtl ? caretEnd - caretPrototype.width : caretEnd;
|
||||
return Offset(dx, box.top);
|
||||
return Offset(min(dx, width), box.top);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -526,7 +526,7 @@ class TextPainter {
|
||||
final TextBox box = boxes.last;
|
||||
final double caretStart = box.start;
|
||||
final double dx = box.direction == TextDirection.rtl ? caretStart - caretPrototype.width : caretStart;
|
||||
return Offset(dx, box.top);
|
||||
return Offset(min(dx, width), box.top);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -426,6 +426,82 @@ void main() {
|
||||
}, skip: !Platform.isLinux);
|
||||
*/
|
||||
|
||||
testWidgets('Overflowing a line with spaces stops the cursor at the end', (WidgetTester tester) async {
|
||||
final TextEditingController controller = TextEditingController();
|
||||
|
||||
await tester.pumpWidget(
|
||||
overlay(
|
||||
child: TextField(
|
||||
key: textFieldKey,
|
||||
controller: controller,
|
||||
maxLines: null,
|
||||
),
|
||||
)
|
||||
);
|
||||
expect(controller.selection.baseOffset, -1);
|
||||
expect(controller.selection.extentOffset, -1);
|
||||
|
||||
const String testValueOneLine = 'enough text to be exactly at the end of the line.';
|
||||
await tester.enterText(find.byType(TextField), testValueOneLine);
|
||||
await skipPastScrollingAnimation(tester);
|
||||
|
||||
RenderBox findInputBox() => tester.renderObject(find.byKey(textFieldKey));
|
||||
|
||||
RenderBox inputBox = findInputBox();
|
||||
final Size oneLineInputSize = inputBox.size;
|
||||
|
||||
await tester.tapAt(textOffsetToPosition(tester, testValueOneLine.length));
|
||||
await tester.pump();
|
||||
|
||||
const String testValueTwoLines = 'enough text to overflow the first line and go to the second';
|
||||
await tester.enterText(find.byType(TextField), testValueTwoLines);
|
||||
await skipPastScrollingAnimation(tester);
|
||||
|
||||
expect(inputBox, findInputBox());
|
||||
inputBox = findInputBox();
|
||||
expect(inputBox.size.height, greaterThan(oneLineInputSize.height));
|
||||
final Size twoLineInputSize = inputBox.size;
|
||||
|
||||
// Enter a string with the same number of characters as testValueTwoLines,
|
||||
// but where the overflowing part is all spaces. Assert that it only renders
|
||||
// on one line.
|
||||
const String testValueSpaces = testValueOneLine + ' ';
|
||||
expect(testValueSpaces.length, testValueTwoLines.length);
|
||||
await tester.enterText(find.byType(TextField), testValueSpaces);
|
||||
await skipPastScrollingAnimation(tester);
|
||||
|
||||
expect(inputBox, findInputBox());
|
||||
inputBox = findInputBox();
|
||||
expect(inputBox.size.height, oneLineInputSize.height);
|
||||
|
||||
// Swapping the final space for a letter causes it to wrap to 2 lines.
|
||||
const String testValueSpacesOverflow = testValueOneLine + ' a';
|
||||
expect(testValueSpacesOverflow.length, testValueTwoLines.length);
|
||||
await tester.enterText(find.byType(TextField), testValueSpacesOverflow);
|
||||
await skipPastScrollingAnimation(tester);
|
||||
|
||||
expect(inputBox, findInputBox());
|
||||
inputBox = findInputBox();
|
||||
expect(inputBox.size.height, twoLineInputSize.height);
|
||||
|
||||
// Positioning the cursor at the end of a line overflowing with spaces puts
|
||||
// it inside the input still.
|
||||
await tester.enterText(find.byType(TextField), testValueSpaces);
|
||||
await skipPastScrollingAnimation(tester);
|
||||
await tester.tapAt(textOffsetToPosition(tester, testValueSpaces.length));
|
||||
await tester.pump();
|
||||
|
||||
final double inputWidth = findRenderEditable(tester).size.width;
|
||||
final Offset cursorOffsetSpaces = findRenderEditable(tester).getLocalRectForCaret(
|
||||
const TextPosition(offset: testValueSpaces.length),
|
||||
).bottomRight;
|
||||
|
||||
// Gap between caret and edge of input, defined in editable.dart.
|
||||
const int _kCaretGap = 1;
|
||||
|
||||
expect(cursorOffsetSpaces.dx, inputWidth - _kCaretGap);
|
||||
});
|
||||
|
||||
testWidgets('obscureText control test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
overlay(
|
||||
|
@ -133,7 +133,9 @@ void main() {
|
||||
Offset caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 0), ui.Rect.zero);
|
||||
expect(caretOffset.dx, 21);
|
||||
caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: text.length), ui.Rect.zero);
|
||||
expect(caretOffset.dx, 441);
|
||||
// The end of the line is 441, but the width is only 420, so the cursor is
|
||||
// stopped there without overflowing.
|
||||
expect(caretOffset.dx, painter.width);
|
||||
|
||||
caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 1), ui.Rect.zero);
|
||||
expect(caretOffset.dx, 35);
|
||||
|
Loading…
x
Reference in New Issue
Block a user