mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Fix: fix the delay of showOnScreen animation when keyboard comes up. (#99546)
This commit is contained in:
parent
f1d8e30c4b
commit
dbbaf68ee4
@ -1965,7 +1965,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
// to make sure the user can see the changes they just made. Programmatical
|
||||
// changes to `textEditingValue` do not trigger the behavior even if the
|
||||
// text field is focused.
|
||||
_scheduleShowCaretOnScreen();
|
||||
_scheduleShowCaretOnScreen(withAnimation: true);
|
||||
if (_hasInputConnection) {
|
||||
// To keep the cursor from blinking while typing, we want to restart the
|
||||
// cursor timer every time a new character is typed.
|
||||
@ -2498,7 +2498,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
|
||||
bool _showCaretOnScreenScheduled = false;
|
||||
|
||||
void _scheduleShowCaretOnScreen() {
|
||||
void _scheduleShowCaretOnScreen({required bool withAnimation}) {
|
||||
if (_showCaretOnScreenScheduled) {
|
||||
return;
|
||||
}
|
||||
@ -2538,17 +2538,23 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
|
||||
final RevealedOffset targetOffset = _getOffsetToRevealCaret(_currentCaretRect!);
|
||||
|
||||
_scrollController.animateTo(
|
||||
targetOffset.offset,
|
||||
duration: _caretAnimationDuration,
|
||||
curve: _caretAnimationCurve,
|
||||
);
|
||||
|
||||
renderEditable.showOnScreen(
|
||||
rect: caretPadding.inflateRect(targetOffset.rect),
|
||||
duration: _caretAnimationDuration,
|
||||
curve: _caretAnimationCurve,
|
||||
);
|
||||
if (withAnimation) {
|
||||
_scrollController.animateTo(
|
||||
targetOffset.offset,
|
||||
duration: _caretAnimationDuration,
|
||||
curve: _caretAnimationCurve,
|
||||
);
|
||||
renderEditable.showOnScreen(
|
||||
rect: caretPadding.inflateRect(targetOffset.rect),
|
||||
duration: _caretAnimationDuration,
|
||||
curve: _caretAnimationCurve,
|
||||
);
|
||||
} else {
|
||||
_scrollController.jumpTo(targetOffset.offset);
|
||||
renderEditable.showOnScreen(
|
||||
rect: caretPadding.inflateRect(targetOffset.rect),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -2561,7 +2567,9 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
_selectionOverlay?.updateForScroll();
|
||||
});
|
||||
if (_lastBottomViewInset < WidgetsBinding.instance.window.viewInsets.bottom) {
|
||||
_scheduleShowCaretOnScreen();
|
||||
// Because the metrics change signal from engine will come here every frame
|
||||
// (on both iOS and Android). So we don't need to show caret with animation.
|
||||
_scheduleShowCaretOnScreen(withAnimation: false);
|
||||
}
|
||||
}
|
||||
_lastBottomViewInset = WidgetsBinding.instance.window.viewInsets.bottom;
|
||||
@ -2745,7 +2753,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
_lastBottomViewInset = WidgetsBinding.instance.window.viewInsets.bottom;
|
||||
if (!widget.readOnly) {
|
||||
_scheduleShowCaretOnScreen();
|
||||
_scheduleShowCaretOnScreen(withAnimation: true);
|
||||
}
|
||||
if (!_value.selection.isValid) {
|
||||
// Place cursor at the end if the selection is invalid when we receive focus.
|
||||
@ -2900,7 +2908,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
? _value.selection != value.selection
|
||||
: _value != value;
|
||||
if (shouldShowCaret) {
|
||||
_scheduleShowCaretOnScreen();
|
||||
_scheduleShowCaretOnScreen(withAnimation: true);
|
||||
}
|
||||
_formatAndSetValue(value, cause, userInteraction: true);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
@ -39,6 +41,26 @@ class _MatchesMethodCall extends Matcher {
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
late TextEditingController controller;
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Node');
|
||||
final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: 'EditableText Scope Node');
|
||||
@ -107,6 +129,51 @@ void main() {
|
||||
expect(tester.testTextInput.setClientArgs!['inputAction'], equals(serializedActionName));
|
||||
}
|
||||
|
||||
// Related issue: https://github.com/flutter/flutter/issues/98115
|
||||
testWidgets('ScheduleShowCaretOnScreen with no animation when the window changes metrics', (WidgetTester tester) async {
|
||||
final ScrollController scrollController = ScrollController();
|
||||
final Widget widget = MaterialApp(
|
||||
home: Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: List<Widget>.generate(
|
||||
5,
|
||||
(_) {
|
||||
return Container(
|
||||
height: 1200.0,
|
||||
color: Colors.black12,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
child: EditableText(
|
||||
controller: TextEditingController(),
|
||||
backgroundCursorColor: Colors.grey,
|
||||
focusNode: focusNode,
|
||||
style: const TextStyle(),
|
||||
cursorColor: Colors.red,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpWidget(widget);
|
||||
await tester.showKeyboard(find.byType(EditableText));
|
||||
TestWidgetsFlutterBinding.instance.window.viewInsetsTestValue = const _TestWindowPadding(bottom: 500);
|
||||
await tester.pump();
|
||||
|
||||
// The offset of the scrollController should change immediately after window changes its metrics.
|
||||
final double offsetAfter = scrollController.offset;
|
||||
expect(offsetAfter, isNot(0.0));
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/34538.
|
||||
testWidgets('RTL arabic correct caret placement after trailing whitespace', (WidgetTester tester) async {
|
||||
final TextEditingController controller = TextEditingController();
|
||||
|
Loading…
Reference in New Issue
Block a user