Disable blinking cursor when EditableText.showCursor
is false (#127562)
Fixes https://github.com/flutter/flutter/issues/108187
This commit is contained in:
parent
9707001c02
commit
37f20c268b
@ -2610,12 +2610,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
final bool newTickerEnabled = TickerMode.of(context);
|
||||
if (_tickersEnabled != newTickerEnabled) {
|
||||
_tickersEnabled = newTickerEnabled;
|
||||
if (_tickersEnabled && _cursorActive) {
|
||||
if (_showBlinkingCursor) {
|
||||
_startCursorBlink();
|
||||
} else if (!_tickersEnabled && _cursorTimer != null) {
|
||||
// Cannot use _stopCursorBlink because it would reset _cursorActive.
|
||||
_cursorTimer!.cancel();
|
||||
_cursorTimer = null;
|
||||
_stopCursorBlink();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2707,6 +2705,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (widget.showCursor != oldWidget.showCursor) {
|
||||
_startOrStopCursorTimerIfNeeded();
|
||||
}
|
||||
final bool canPaste = widget.selectionControls is TextSelectionHandleControls
|
||||
? pasteEnabled
|
||||
: widget.selectionControls?.canPaste(this) ?? false;
|
||||
@ -3655,6 +3657,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
_cursorVisibilityNotifier.value = widget.showCursor && _cursorBlinkOpacityController.value > 0;
|
||||
}
|
||||
|
||||
bool get _showBlinkingCursor => _hasFocus && _value.selection.isCollapsed && widget.showCursor && _tickersEnabled;
|
||||
|
||||
/// Whether the blinking cursor is actually visible at this precise moment
|
||||
/// (it's hidden half the time, since it blinks).
|
||||
@visibleForTesting
|
||||
@ -3673,13 +3677,11 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
int _obscureShowCharTicksPending = 0;
|
||||
int? _obscureLatestCharIndex;
|
||||
|
||||
// Indicates whether the cursor should be blinking right now (but it may
|
||||
// actually not blink because it's disabled via TickerMode.of(context)).
|
||||
bool _cursorActive = false;
|
||||
|
||||
void _startCursorBlink() {
|
||||
assert(!(_cursorTimer?.isActive ?? false) || !(_backingCursorBlinkOpacityController?.isAnimating ?? false));
|
||||
_cursorActive = true;
|
||||
if (!widget.showCursor) {
|
||||
return;
|
||||
}
|
||||
if (!_tickersEnabled) {
|
||||
return;
|
||||
}
|
||||
@ -3719,7 +3721,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
}
|
||||
|
||||
void _stopCursorBlink({ bool resetCharTicks = true }) {
|
||||
_cursorActive = false;
|
||||
_cursorBlinkOpacityController.value = 0.0;
|
||||
_cursorTimer?.cancel();
|
||||
_cursorTimer = null;
|
||||
@ -3729,11 +3730,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
}
|
||||
|
||||
void _startOrStopCursorTimerIfNeeded() {
|
||||
if (_cursorTimer == null && _hasFocus && _value.selection.isCollapsed) {
|
||||
_startCursorBlink();
|
||||
}
|
||||
else if (_cursorActive && (!_hasFocus || !_value.selection.isCollapsed)) {
|
||||
if (!_showBlinkingCursor) {
|
||||
_stopCursorBlink();
|
||||
} else if (_cursorTimer == null) {
|
||||
_startCursorBlink();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -771,6 +771,54 @@ void main() {
|
||||
await checkCursorBlinking();
|
||||
});
|
||||
|
||||
testWidgets('Turning showCursor off stops the cursor', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/108187.
|
||||
final bool debugDeterministicCursor = EditableText.debugDeterministicCursor;
|
||||
// This doesn't really matter.
|
||||
EditableText.debugDeterministicCursor = false;
|
||||
addTearDown(() { EditableText.debugDeterministicCursor = debugDeterministicCursor; });
|
||||
const Key key = Key('EditableText');
|
||||
|
||||
Widget buildEditableText({ required bool showCursor }) {
|
||||
return MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: EditableText(
|
||||
key: key,
|
||||
backgroundCursorColor: Colors.grey,
|
||||
// Use animation controller to animate cursor blink for testing.
|
||||
cursorOpacityAnimates: true,
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
style: textStyle,
|
||||
cursorColor: cursorColor,
|
||||
showCursor: showCursor,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
late final EditableTextState editableTextState = tester.state(find.byKey(key));
|
||||
await tester.pumpWidget(buildEditableText(showCursor: false));
|
||||
await tester.tap(find.byKey(key));
|
||||
await tester.pump();
|
||||
|
||||
// No cursor even when focused.
|
||||
expect(editableTextState.cursorCurrentlyVisible, false);
|
||||
|
||||
// The EditableText still has focus, so the cursor should starts blinking.
|
||||
await tester.pumpWidget(buildEditableText(showCursor: true));
|
||||
expect(editableTextState.cursorCurrentlyVisible, true);
|
||||
await tester.pump();
|
||||
expect(editableTextState.cursorCurrentlyVisible, true);
|
||||
|
||||
// readOnly disables blinking cursor.
|
||||
await tester.pumpWidget(buildEditableText(showCursor: false));
|
||||
expect(editableTextState.cursorCurrentlyVisible, false);
|
||||
await tester.pump();
|
||||
expect(editableTextState.cursorCurrentlyVisible, false);
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/pull/30475.
|
||||
testWidgets('Trying to select with the floating cursor does not crash', (WidgetTester tester) async {
|
||||
const String text = 'hello world this is fun and cool and awesome!';
|
||||
|
Loading…
x
Reference in New Issue
Block a user