Skip to content

Commit c105708

Browse files
authored
RTL caret position (flutter#60009)
1 parent fc64e75 commit c105708

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

packages/flutter/lib/src/painting/text_painter.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,9 @@ class TextPainter {
563563
}
564564
_lastMinWidth = minWidth;
565565
_lastMaxWidth = maxWidth;
566+
// A change in layout invalidates the cached caret metrics as well.
567+
_previousCaretPosition = null;
568+
_previousCaretPrototype = null;
566569
_paragraph.layout(ui.ParagraphConstraints(width: maxWidth));
567570
if (minWidth != maxWidth) {
568571
final double newWidth = maxIntrinsicWidth.clamp(minWidth, maxWidth) as double;

packages/flutter/test/material/text_field_test.dart

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ void main() {
143143
const String kMoreThanFourLines =
144144
kThreeLines +
145145
"\nFourth line won't display and ends at";
146+
// Gap between caret and edge of input, defined in editable.dart.
147+
const int kCaretGap = 1;
146148

147149
setUp(() async {
148150
debugResetSemanticsIdCounter();
@@ -754,10 +756,7 @@ void main() {
754756
const TextPosition(offset: testValueSpaces.length),
755757
).bottomRight;
756758

757-
// Gap between caret and edge of input, defined in editable.dart.
758-
const int _kCaretGap = 1;
759-
760-
expect(cursorOffsetSpaces.dx, inputWidth - _kCaretGap);
759+
expect(cursorOffsetSpaces.dx, inputWidth - kCaretGap);
761760
});
762761

763762
testWidgets('mobile obscureText control test', (WidgetTester tester) async {
@@ -8011,4 +8010,63 @@ void main() {
80118010
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
80128011
await gesture.moveTo(center);
80138012
});
8013+
8014+
testWidgets('Caret rtl with changing width', (WidgetTester tester) async {
8015+
StateSetter setState;
8016+
bool isWide = false;
8017+
const double wideWidth = 300.0;
8018+
const double narrowWidth = 200.0;
8019+
final TextEditingController controller = TextEditingController();
8020+
await tester.pumpWidget(
8021+
boilerplate(
8022+
child: StatefulBuilder(
8023+
builder: (BuildContext context, StateSetter setter) {
8024+
setState = setter;
8025+
return Container(
8026+
width: isWide ? wideWidth : narrowWidth,
8027+
child: TextField(
8028+
key: textFieldKey,
8029+
controller: controller,
8030+
textDirection: TextDirection.rtl,
8031+
),
8032+
);
8033+
}
8034+
),
8035+
),
8036+
);
8037+
8038+
// The cursor is on the right of the input because it's RTL.
8039+
RenderEditable editable = findRenderEditable(tester);
8040+
double cursorRight = editable.getLocalRectForCaret(
8041+
TextPosition(offset: controller.value.text.length),
8042+
).topRight.dx;
8043+
double inputWidth = editable.size.width;
8044+
expect(inputWidth, narrowWidth);
8045+
expect(cursorRight, inputWidth - kCaretGap);
8046+
8047+
// After entering some text, the cursor remains on the right of the input.
8048+
await tester.enterText(find.byType(TextField), '12345');
8049+
await tester.pump();
8050+
editable = findRenderEditable(tester);
8051+
cursorRight = editable.getLocalRectForCaret(
8052+
TextPosition(offset: controller.value.text.length),
8053+
).topRight.dx;
8054+
inputWidth = editable.size.width;
8055+
expect(cursorRight, inputWidth - kCaretGap);
8056+
8057+
// Since increasing the width of the input moves its right edge further to
8058+
// the right, the cursor has followed this change and still appears on the
8059+
// right of the input.
8060+
setState(() {
8061+
isWide = true;
8062+
});
8063+
await tester.pump();
8064+
editable = findRenderEditable(tester);
8065+
cursorRight = editable.getLocalRectForCaret(
8066+
TextPosition(offset: controller.value.text.length),
8067+
).topRight.dx;
8068+
inputWidth = editable.size.width;
8069+
expect(inputWidth, wideWidth);
8070+
expect(cursorRight, inputWidth - kCaretGap);
8071+
});
80148072
}

0 commit comments

Comments
 (0)