Call bringIntoView after RenderEditable updates on paste (#98604)
This commit is contained in:
parent
edc16121f9
commit
533a5dde96
@ -1689,7 +1689,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
Clipboard.setData(ClipboardData(text: selection.textInside(text)));
|
||||
_replaceText(ReplaceTextIntent(textEditingValue, '', selection, cause));
|
||||
if (cause == SelectionChangedCause.toolbar) {
|
||||
bringIntoView(textEditingValue.selection.extent);
|
||||
// Schedule a call to bringIntoView() after renderEditable updates.
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
bringIntoView(textEditingValue.selection.extent);
|
||||
});
|
||||
hideToolbar();
|
||||
}
|
||||
_clipboardStatus?.update();
|
||||
@ -1715,7 +1718,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
|
||||
_replaceText(ReplaceTextIntent(textEditingValue, data.text!, selection, cause));
|
||||
if (cause == SelectionChangedCause.toolbar) {
|
||||
bringIntoView(textEditingValue.selection.extent);
|
||||
// Schedule a call to bringIntoView() after renderEditable updates.
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
bringIntoView(textEditingValue.selection.extent);
|
||||
});
|
||||
hideToolbar();
|
||||
}
|
||||
}
|
||||
@ -3095,10 +3101,20 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
}
|
||||
|
||||
void _replaceText(ReplaceTextIntent intent) {
|
||||
userUpdateTextEditingValue(
|
||||
intent.currentTextEditingValue.replaced(intent.replacementRange, intent.replacementText),
|
||||
intent.cause,
|
||||
final TextEditingValue oldValue = _value;
|
||||
final TextEditingValue newValue = intent.currentTextEditingValue.replaced(
|
||||
intent.replacementRange,
|
||||
intent.replacementText,
|
||||
);
|
||||
userUpdateTextEditingValue(newValue, intent.cause);
|
||||
|
||||
// If there's no change in text and selection (e.g. when selecting and
|
||||
// pasting identical text), the widget won't be rebuilt on value update.
|
||||
// Handle this by calling _didChangeTextEditingValue() so caret and scroll
|
||||
// updates can happen.
|
||||
if (newValue == oldValue) {
|
||||
_didChangeTextEditingValue();
|
||||
}
|
||||
}
|
||||
late final Action<ReplaceTextIntent> _replaceTextAction = CallbackAction<ReplaceTextIntent>(onInvoke: _replaceText);
|
||||
|
||||
|
@ -10948,12 +10948,12 @@ void main() {
|
||||
|
||||
// Paste
|
||||
await resetSelectionAndScrollOffset();
|
||||
textSelectionDelegate.pasteText(SelectionChangedCause.keyboard);
|
||||
await textSelectionDelegate.pasteText(SelectionChangedCause.keyboard);
|
||||
await tester.pump();
|
||||
expect(scrollController.offset, maxScrollExtent);
|
||||
|
||||
await resetSelectionAndScrollOffset();
|
||||
textSelectionDelegate.pasteText(SelectionChangedCause.toolbar);
|
||||
await textSelectionDelegate.pasteText(SelectionChangedCause.toolbar);
|
||||
await tester.pump();
|
||||
expect(scrollController.offset.roundToDouble(), 0.0);
|
||||
|
||||
@ -10980,6 +10980,50 @@ void main() {
|
||||
expect(scrollController.offset.roundToDouble(), 0.0);
|
||||
});
|
||||
|
||||
testWidgets('Should not scroll on paste if caret already visible', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/96658.
|
||||
final ScrollController scrollController = ScrollController();
|
||||
final TextEditingController controller = TextEditingController(
|
||||
text: 'Lorem ipsum please paste here: \n${".\n" * 50}',
|
||||
);
|
||||
final FocusNode focusNode = FocusNode();
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Center(
|
||||
child: SizedBox(
|
||||
height: 600.0,
|
||||
width: 600.0,
|
||||
child: EditableText(
|
||||
controller: controller,
|
||||
scrollController: scrollController,
|
||||
focusNode: focusNode,
|
||||
maxLines: null,
|
||||
style: const TextStyle(fontSize: 36.0),
|
||||
backgroundCursorColor: Colors.grey,
|
||||
cursorColor: cursorColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
await Clipboard.setData(const ClipboardData(text: 'Fairly long text to be pasted'));
|
||||
focusNode.requestFocus();
|
||||
|
||||
final EditableTextState state =
|
||||
tester.state<EditableTextState>(find.byType(EditableText));
|
||||
|
||||
expect(scrollController.offset, 0.0);
|
||||
|
||||
controller.selection = const TextSelection.collapsed(offset: 31);
|
||||
await state.pasteText(SelectionChangedCause.toolbar);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// No scroll should happen as the caret is in the viewport all the time.
|
||||
expect(scrollController.offset, 0.0);
|
||||
});
|
||||
|
||||
testWidgets('Autofill enabled by default', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode();
|
||||
await tester.pumpWidget(
|
||||
|
Loading…
x
Reference in New Issue
Block a user