-
Notifications
You must be signed in to change notification settings - Fork 247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SuperEditor][SuperTextField][iOS] Allow animating caret blink (Resolves #2099) #2238
base: main
Are you sure you want to change the base?
Conversation
@matthew-carroll Can you take a look at the questions mentioned in the PR description? |
/// | ||
/// If [animate] is `true`, the caret animates its [opacity] when switching | ||
/// between visible and invisible. If [animate] is `false`, the caret | ||
/// switches between fully opaque and fully transparent. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also add a point here about performance? The reason we originally got rid of animated blinking was to reduce Flutter re-renders.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was the original performance issue really about re-renders? Or was it related to repaints? I'm wondering if using e RepaintBoundary
in our overlayers would make a difference.
bool animate = false, | ||
Duration fadeDuration = const Duration(milliseconds: 200), | ||
}) : _flashPeriod = flashPeriod, | ||
_fadeDuration = fadeDuration, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How can the fade duration be independent of the flash period?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The caret isn't constantly fading in and out. It stays visible or invisible during the flash period, then quickly fades in/out.
Should we just use half of the flash period?
@@ -62,8 +76,24 @@ class BlinkController with ChangeNotifier { | |||
notifyListeners(); | |||
} | |||
|
|||
/// Whether or not the caret is currently visible. | |||
/// | |||
/// It's possible that [isVisible] is `false` while [opacity] is greater than `0.0` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than sayign something is possible, please describe under which circumstances something happens or doesn't happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
double get opacity => _opacity; | ||
double _opacity = 1.0; | ||
|
||
/// Whether or not the caret should animate its opacity. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also specify the alternative. It's possible a developer reads this and then asks "what does it mean to not animate the opacity?" - let's make the distinction between fading blinking vs on/off blinking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updates.
/// Whether or not the caret should animate its opacity. | ||
bool _animate = false; | ||
|
||
/// Whether or not the caret should maintain its opacity until the next blink. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This Dart Doc comment makes it sound like this property is a permanent configuration on this controller, but in fact it looks like a momentary flag that's switched on and off to capture the fact that we're at a specific moment in time. Please try to replace this description with one that describes what this property is tracking, including when we expect it to flip from true to false, or false to true. Also, the name of this should probably start with _isSomething...
, if it represents a temporary condition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to improve it a little bit.
@@ -118,6 +156,12 @@ class BlinkController with ChangeNotifier { | |||
} | |||
|
|||
void _onTick(Duration elapsedTime) { | |||
if (isBlinking && _animate && !_remainOpaqueUntilNextBlink) { | |||
final percentage = ((elapsedTime - _lastBlinkTime).inMilliseconds / _fadeDuration.inMilliseconds).clamp(0.0, 1.0); | |||
_opacity = _isVisible ? percentage : 1 - percentage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment to clarify the meaning of _isVisible
in this calculation, because you're actually using it as a proxy to decide whether we're "fading in" or "fading out", and that's not immediately obvious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
My initial thought is, no. I think we should adjust the Super Editor side to play well with common test behaviors, rather than change the test behaviors to fit Super Editor.
I wanna make sure I understand this question - you exposed the property from the controller already, right? |
But how should we do that, if the ticker is constantly scheduling frames?
I exposed from the controller, but it still isn't configurable in a way that apps can enable or disable it. The |
[SuperEditor][SuperTextField][iOS] Allow animating caret blink. Resolves #2099
Currently, our blinking caret has an on/off visibility, it doesn't animates the visibility changes.
This PR adds a fade in/out transition when the caret switches from visible to invisible.
Some problems that I found:
Ticker
to drive the visibility change, we are setting the_ticker
tonull
whenstopBlinking
is called. It means that once the user types or places the caret somewhere, which causesstopBlinking
to be called to momentary stop blinking, we are switching to the timer mode:super_editor/super_text_layout/lib/src/infrastructure/blink_controller.dart
Lines 90 to 96 in 4c7472b
super_editor/super_text_layout/lib/src/infrastructure/blink_controller.dart
Lines 68 to 88 in 4c7472b
pumpAndSettleTimeout
. The timeout happens because two methods used in those tests (tester.ime.backspace
andtester.doubleTapInParagraph
) internally callpumpAndSettle
.Open questions:
SuperEditorIosControlsController
?tester.ime.backspace
andtester.doubleTapInParagraph
to avoid callingpumpAndSettle
?