Unverified Commit 497fc106 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Text selection toolbar position after keyboard opens (#86439)

parent 6eb59418
......@@ -2272,8 +2272,13 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
@override
void didChangeMetrics() {
if (_lastBottomViewInset < WidgetsBinding.instance!.window.viewInsets.bottom) {
_scheduleShowCaretOnScreen();
if (_lastBottomViewInset != WidgetsBinding.instance!.window.viewInsets.bottom) {
SchedulerBinding.instance!.addPostFrameCallback((Duration _) {
_selectionOverlay?.updateForScroll();
});
if (_lastBottomViewInset < WidgetsBinding.instance!.window.viewInsets.bottom) {
_scheduleShowCaretOnScreen();
}
}
_lastBottomViewInset = WidgetsBinding.instance!.window.viewInsets.bottom;
}
......
......@@ -3,7 +3,7 @@
// found in the LICENSE file.
import 'dart:math' as math;
import 'dart:ui' as ui show window, BoxHeightStyle, BoxWidthStyle;
import 'dart:ui' as ui show window, BoxHeightStyle, BoxWidthStyle, WindowPadding;
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
......@@ -148,6 +148,26 @@ class TestFormatter extends TextInputFormatter {
}
}
// Used to set window.viewInsets since the real ui.WindowPadding has only a
// private constructor.
class _TestWindowPadding implements ui.WindowPadding {
const _TestWindowPadding({
required this.bottom,
});
@override
final double bottom;
@override
double get top => 0.0;
@override
double get left => 0.0;
@override
double get right => 0.0;
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
......@@ -2126,6 +2146,77 @@ void main() {
skip: isContextMenuProvidedByPlatform,
);
testWidgets(
'the toolbar adjusts its position above/below when bottom inset changes',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 48.0,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IntrinsicHeight(
child: TextField(
controller: controller,
expands: true,
minLines: null,
maxLines: null,
),
),
const SizedBox(height: 325.0),
],
),
),
),
),
),
);
const String testValue = 'abc def ghi';
await tester.enterText(find.byType(TextField), testValue);
await skipPastScrollingAnimation(tester);
await _showSelectionMenuAt(tester, controller, testValue.indexOf('e'));
// Verify the selection toolbar position is above the text.
expect(find.text('Select all'), findsOneWidget);
Offset toolbarTopLeft = tester.getTopLeft(find.text('Select all'));
Offset textFieldTopLeft = tester.getTopLeft(find.byType(TextField));
expect(toolbarTopLeft.dy, lessThan(textFieldTopLeft.dy));
// Add a viewInset tall enough to push the field to the top, where there
// is no room to display the toolbar above. This is similar to when the
// keyboard is shown.
tester.binding.window.viewInsetsTestValue = const _TestWindowPadding(
bottom: 500.0,
);
addTearDown(tester.binding.window.clearViewInsetsTestValue);
await tester.pumpAndSettle();
// Verify the selection toolbar position is below the text.
toolbarTopLeft = tester.getTopLeft(find.text('Select all'));
textFieldTopLeft = tester.getTopLeft(find.byType(TextField));
expect(toolbarTopLeft.dy, greaterThan(textFieldTopLeft.dy));
// Remove the viewInset, as if the keyboard were hidden.
tester.binding.window.clearViewInsetsTestValue();
await tester.pumpAndSettle();
// Verify the selection toolbar position is below the text.
toolbarTopLeft = tester.getTopLeft(find.text('Select all'));
textFieldTopLeft = tester.getTopLeft(find.byType(TextField));
expect(toolbarTopLeft.dy, lessThan(textFieldTopLeft.dy));
},
skip: isContextMenuProvidedByPlatform,
);
testWidgets(
'Toolbar appears in the right places in multiline inputs',
(WidgetTester tester) async {
......
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