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 caretEnd = box.end;
|
||||||
final double dx = box.direction == TextDirection.rtl ? caretEnd - caretPrototype.width : caretEnd;
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
@ -526,7 +526,7 @@ class TextPainter {
|
|||||||
final TextBox box = boxes.last;
|
final TextBox box = boxes.last;
|
||||||
final double caretStart = box.start;
|
final double caretStart = box.start;
|
||||||
final double dx = box.direction == TextDirection.rtl ? caretStart - caretPrototype.width : caretStart;
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -426,6 +426,82 @@ void main() {
|
|||||||
}, skip: !Platform.isLinux);
|
}, 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 {
|
testWidgets('obscureText control test', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
overlay(
|
overlay(
|
||||||
|
@ -133,7 +133,9 @@ void main() {
|
|||||||
Offset caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 0), ui.Rect.zero);
|
Offset caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 0), ui.Rect.zero);
|
||||||
expect(caretOffset.dx, 21);
|
expect(caretOffset.dx, 21);
|
||||||
caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: text.length), ui.Rect.zero);
|
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);
|
caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 1), ui.Rect.zero);
|
||||||
expect(caretOffset.dx, 35);
|
expect(caretOffset.dx, 35);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user