-
Notifications
You must be signed in to change notification settings - Fork 29.1k
animate cupertino time picker hour label #172850
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
base: master
Are you sure you want to change the base?
Conversation
Some time ago, I opened a PR related to this(#164292), but my implementation differed from the native one. Now I'm bringing a new implementation that replicates the native behavior and will work for any suffix, supporting languages beyond English. I still need to make a few adjustments to the golden test, but overall, I believe it's ready for review. |
Awesome! I'll take a look. |
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.
Hi, @MaironLucas, thanks for the PR. Can you run dart format packages/flutter/lib/src/cupertino/date_picker.dart
to fix the CI failures?
d7712fb
to
1b990f0
Compare
Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change). If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
@@ -53,6 +53,10 @@ const double _kTimerPickerLabelFontSize = 17.0; | |||
// The width of each column of the countdown time picker. | |||
const double _kTimerPickerColumnIntrinsicWidth = 106; | |||
|
|||
// Value derived using a video captured from the Clock app and a video editor to | |||
// analyze animation duration. | |||
const Duration _kTimePickerLabelAnimationDuration = Duration(milliseconds: 200); |
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 specify what iOS device and version this value was observed on?
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.
@dkwingsmt, could you help me with that? I used the video that you put in this comment to find this value.
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.
Sure! It's an iPhone 16 pro running iOS 18.
- Add AnimatedSwitcher to animate the label of hour when the picker changes ref flutter#27515
Golden file changes are available for triage from new commit, Click here to view. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
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.
Sorry for the late review!
In general looks great (I love the findAnimatedLabelWithText
util function and how the text is shown after splitting).
@@ -53,6 +53,10 @@ const double _kTimerPickerLabelFontSize = 17.0; | |||
// The width of each column of the countdown time picker. | |||
const double _kTimerPickerColumnIntrinsicWidth = 106; | |||
|
|||
// Value derived using a video captured from the Clock app and a video editor to | |||
// analyze animation duration. | |||
const Duration _kTimePickerLabelAnimationDuration = Duration(milliseconds: 200); |
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.
Sure! It's an iPhone 16 pro running iOS 18.
/// | ||
/// [labelBuilder] is a function that takes a value and returns the full label text. | ||
/// [currentValue] is the current value to display. | ||
/// [baseValue] is the value used to split the label into prefix and suffix. |
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.
Since baseValue
is always 1, i recommend removing it from _buildAnimatedLabel
's parameters and just say final String baseLabel = labelBuilder(1);
with a short comment.
}) { | ||
final String baseLabel = labelBuilder(baseValue); | ||
final String currentLabel = labelBuilder(currentValue); | ||
final List<String> parts = currentLabel.split(baseLabel); |
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.
Instead of split
, use currentLabel.substring(baseLabel.length)
, which is IMO clearer and also avoids a (not-yet-existing) problem where baseLabel
appears for multiple times.
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.
Also, add a comment that we only support the case where baseLabel
is a prefix of (or equal to) currentLabel
, since we haven't observed other cases.
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.
Also, if you want to be super safe, instead of showing baseLabel
as the prefix, show currentLabel.substring(0, baseLabel.length)
to avoid the (not-yet-existing) problem where baseLabel
is not a prefix.
child: AnimatedSwitcher( | ||
duration: _kTimePickerLabelAnimationDuration, | ||
transitionBuilder: (Widget child, Animation<double> animation) { | ||
return FadeTransition(opacity: animation, child: child); |
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 explain why you need the custom transition builder to remove the key from the FadeTransition
?
@@ -2636,6 +2657,66 @@ void main() { | |||
lastOffset = tester.getTopLeft(find.text('11')); | |||
expect(tester.getTopLeft(find.text('2022')).dy, lastOffset.dy); | |||
}); | |||
|
|||
group('CupertinoTimerPicker hour label animation', () { | |||
testWidgets('animates from plural to singular when scrolling from 2 to 1', ( |
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.
It seems to me that these tests would also pass if the text is not animated. If so, can you think of a way to test it? Maybe find the FadeTransition
/ RenderAnimatedOpacity
around the s
text and verify its opacity
?
This PR adds the
buildAnimatedLabel
function to the CupertinoTimePicker widget, allowing the creation of a label with a FadeTransition in this component. It also uses this new function to build de hour label, because this label has this animation in the native implementation, as can be seen in the below visual reference:trim.D05A047A-23D4-482B-A85D-A84FE2FD725F.MOV
Closes #27515
time-picker-before.mp4
time-picker-after.mp4
Pre-launch Checklist
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.