Commit f8c4a6e0 authored by Jason Simmons's avatar Jason Simmons Committed by GitHub

Defer the animation of text fields to the caret position (#10782)

Fixes https://github.com/flutter/flutter/issues/10681
parent 95eba52e
...@@ -460,11 +460,13 @@ class EditableTextState extends State<EditableText> implements TextInputClient { ...@@ -460,11 +460,13 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
// selection, then scroll the caret into view. // selection, then scroll the caret into view.
if (_textChangedSinceLastCaretUpdate) { if (_textChangedSinceLastCaretUpdate) {
_textChangedSinceLastCaretUpdate = false; _textChangedSinceLastCaretUpdate = false;
_scrollController.animateTo( scheduleMicrotask(() {
_getScrollOffsetForCaret(caretRect), _scrollController.animateTo(
curve: Curves.fastOutSlowIn, _getScrollOffsetForCaret(caretRect),
duration: const Duration(milliseconds: 50), curve: Curves.fastOutSlowIn,
); duration: const Duration(milliseconds: 50),
);
});
} }
} }
......
...@@ -38,6 +38,11 @@ Widget overlay(Widget child) { ...@@ -38,6 +38,11 @@ Widget overlay(Widget child) {
); );
} }
Future<Null> skipPastScrollingAnimation(WidgetTester tester) async {
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
}
void main() { void main() {
final MockClipboard mockClipboard = new MockClipboard(); final MockClipboard mockClipboard = new MockClipboard();
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall); SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
...@@ -112,8 +117,7 @@ void main() { ...@@ -112,8 +117,7 @@ void main() {
expect(textFieldValue, equals(testValue)); expect(textFieldValue, equals(testValue));
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
}); });
} }
...@@ -219,8 +223,7 @@ void main() { ...@@ -219,8 +223,7 @@ void main() {
await tester.enterText(find.byType(TextField), testValue); await tester.enterText(find.byType(TextField), testValue);
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
// Tap to reposition the caret. // Tap to reposition the caret.
final int tapIndex = testValue.indexOf('e'); final int tapIndex = testValue.indexOf('e');
...@@ -263,8 +266,7 @@ void main() { ...@@ -263,8 +266,7 @@ void main() {
expect(controller.value.text, testValue); expect(controller.value.text, testValue);
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
expect(controller.selection.isCollapsed, true); expect(controller.selection.isCollapsed, true);
...@@ -299,8 +301,7 @@ void main() { ...@@ -299,8 +301,7 @@ void main() {
await tester.enterText(find.byType(TextField), testValue); await tester.enterText(find.byType(TextField), testValue);
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
// Long press the 'e' to select 'def'. // Long press the 'e' to select 'def'.
final Offset ePos = textOffsetToPosition(tester, testValue.indexOf('e')); final Offset ePos = textOffsetToPosition(tester, testValue.indexOf('e'));
...@@ -362,8 +363,7 @@ void main() { ...@@ -362,8 +363,7 @@ void main() {
final String testValue = 'abc def ghi'; final String testValue = 'abc def ghi';
await tester.enterText(find.byType(TextField), testValue); await tester.enterText(find.byType(TextField), testValue);
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
// Tap the selection handle to bring up the "paste / select all" menu. // Tap the selection handle to bring up the "paste / select all" menu.
await tester.tapAt(textOffsetToPosition(tester, testValue.indexOf('e'))); await tester.tapAt(textOffsetToPosition(tester, testValue.indexOf('e')));
...@@ -382,8 +382,7 @@ void main() { ...@@ -382,8 +382,7 @@ void main() {
// COPY should reset the selection. // COPY should reset the selection.
await tester.tap(find.text('COPY')); await tester.tap(find.text('COPY'));
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
expect(controller.selection.isCollapsed, true); expect(controller.selection.isCollapsed, true);
// Tap again to bring back the menu. // Tap again to bring back the menu.
...@@ -418,8 +417,7 @@ void main() { ...@@ -418,8 +417,7 @@ void main() {
final String testValue = 'abc def ghi'; final String testValue = 'abc def ghi';
await tester.enterText(find.byType(TextField), testValue); await tester.enterText(find.byType(TextField), testValue);
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
// Tap the selection handle to bring up the "paste / select all" menu. // Tap the selection handle to bring up the "paste / select all" menu.
await tester.tapAt(textOffsetToPosition(tester, testValue.indexOf('e'))); await tester.tapAt(textOffsetToPosition(tester, testValue.indexOf('e')));
...@@ -532,8 +530,7 @@ void main() { ...@@ -532,8 +530,7 @@ void main() {
await tester.enterText(find.byType(TextField), testValue); await tester.enterText(find.byType(TextField), testValue);
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
// Check that the text spans multiple lines. // Check that the text spans multiple lines.
final Offset firstPos = textOffsetToPosition(tester, testValue.indexOf('First')); final Offset firstPos = textOffsetToPosition(tester, testValue.indexOf('First'));
...@@ -1340,8 +1337,7 @@ void main() { ...@@ -1340,8 +1337,7 @@ void main() {
await tester.enterText(find.byType(TextField), 'a1b\n2c3'); await tester.enterText(find.byType(TextField), 'a1b\n2c3');
expect(textController.text, '123'); expect(textController.text, '123');
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
await tester.tapAt(textOffsetToPosition(tester, '123'.indexOf('2'))); await tester.tapAt(textOffsetToPosition(tester, '123'.indexOf('2')));
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
...@@ -1382,8 +1378,7 @@ void main() { ...@@ -1382,8 +1378,7 @@ void main() {
final String longText = 'a' * 20; final String longText = 'a' * 20;
await tester.enterText(find.byType(TextField), longText); await tester.enterText(find.byType(TextField), longText);
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
ScrollableState scrollableState = tester.firstState(find.byType(Scrollable)); ScrollableState scrollableState = tester.firstState(find.byType(Scrollable));
expect(scrollableState.position.pixels, equals(0.0)); expect(scrollableState.position.pixels, equals(0.0));
...@@ -1392,8 +1387,7 @@ void main() { ...@@ -1392,8 +1387,7 @@ void main() {
// scrolls to make the caret visible. // scrolls to make the caret visible.
controller.selection = new TextSelection.collapsed(offset: longText.length); controller.selection = new TextSelection.collapsed(offset: longText.length);
await tester.pumpWidget(builder()); await tester.pumpWidget(builder());
// skip past scrolling animation await skipPastScrollingAnimation(tester);
await tester.pump(const Duration(milliseconds: 200));
scrollableState = tester.firstState(find.byType(Scrollable)); scrollableState = tester.firstState(find.byType(Scrollable));
expect(scrollableState.position.pixels, isNot(equals(0.0))); expect(scrollableState.position.pixels, isNot(equals(0.0)));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment