Transitioning from the “Now Playing” screen to the mini-player
Everything looks okay. So we can hide the mini-player, for now.
Mini_Player.opacity = 0
opacity because we’ll want to animate it.
But we also don’t want it to be tapped by accident when the user swipes down the “Now Playing” screen, so we also switch off its
Mini_Player.visible = no
Later we’ll need to know when the mini-player is in use (you’ll see why). We create a variable for that,
miniPlayerActive, which at this point will still be ‘
miniPlayerActive = no
To know when the user has dragged down the “Now Playing” screen we’ll listen to its
onScrollEnd event. This event gets triggered the moment the user stops scrolling.
Now we need to check if the user has scrolled down far enough. If they haven’t, we’ll just let the ScrollComponent bounce back.
In the original app, the user has to drag the “Now Playing” screen 121 points or more from the top of the screen to have it transition to the mini-player.
The “Now Playing” screen is already placed 33 points from the top, so we’ll start our animation when the user has scrolled down
But since we’re scrolling down, and not up like as we would normally (which is also why there’s some scroll resistance), we’re checking for a negative value of
scrollY, the scroll distance.
But since we’re scrolling down, actually beyond the edge of the content, we’re checking for a negative value of
scrollY, the scroll distance.
(You can put a
print maxi_player.scrollY in the event handler to test this.)
scroll_now_playing.onScrollEnd -> if scroll_now_playing.scrollY < -88
Now, when the user has scrolled this far down we can start the transition, but we face a problem: the “Now Playing” screen will be in a “scrolled down” state.
We’ll solve this by quickly resetting the ScrollComponent to its initial state, like this:
Before starting the animations, we’ll move the ScrollComponent down while moving its content up. We do it instantly, without animation.
Okay, step by step:
# The ScrollComponent jumps to its content’s position scroll_now_playing.y = scroll_now_playing.content.y + 33
(Note that we’re not using
scrollY here, but the
y position, which increases when scrolling down.)
So no matter how far the user has scrolled down, our ScrollComponent will always end up in the correct place.
Now we move the content back to the top:
# … and we reset the content to its initial position scroll_now_playing.scrollToPoint y: 0 no
scrollToPoint() function does what it says: it lets you scroll to a certain point. By setting its ‘animate’ argument to
no, this will happen instantly, without animation.
All together it should look like this:
scroll_now_playing.onScrollEnd -> if scroll_now_playing.scrollY < -88 scroll_now_playing.y = scroll_now_playing.content.y + 33 scroll_now_playing.scrollToPoint y: 0 no
Please try it. You can scroll up and down all you want, but once you pull down far enough, it will stay at the spot where you released it.
Now get ready. We’ll have nine animations, with different timings, all run at the same time.
The first set of six animations starts immediately, and the duration for all of them will be a third of a second.
# - First set of animations: a third of a second - # firstSetDuration = 0.3
0.3 seconds we’ll:
- Show the mini-player (
- Hide the transparent gray overlay behind it (
- Reset the “Library” screen in the back (
- … and do the same for the “For You” screen
- Make the Status Bar black again (
- And move the Tab Bar up (
Here we go.
Showing the mini-player: We make it
visible again and animate its
opacity back to
Mini_Player.visible = yes Mini_Player.animate opacity: 1 options: time: firstSetDuration
Hide the transparent gray overlay by animating its
opacity to zero.
overlay.animate opacity: 0 options: time: firstSetDuration
Next, we move
scroll_for_you back to the top of the screen, reset their horizontal scale, and remove their border radius.
scroll_library.animate scaleX: 1 y: 0 borderRadius: 0 options: time: firstSetDuration scroll_for_you.animate scaleX: 1 y: 0 borderRadius: 0 options: time: firstSetDuration
(Initially, we only changed
scroll_library, but after use of the prototype either one of them might be in the background.)
Earlier we made the Status Bar white by changing its
invert; we now dial it back to the default value:
$.Status_Bar.animate invert: 0 options: time: firstSetDuration
By setting the Tab Bar’s bottom,
maxY, to the bottom of the screen, it will slide back up.
$.Tabs.animate maxY: Screen.height options: time: firstSetDuration
Because we used a variable,
firstSetDuration, to set the duration for these animations, we can slow all of them down to better observe what’s happening.
Like having them animate with a duration of 3 seconds:
# - First set of animations: a third of a second - # firstSetDuration = 0.3 * 10
The next two animations also start immediately but are slower, and they have a subtle bounce.
# - Second set of animations: 0.7 seconds - # secondSetDuration = 0.7
0.7 seconds we’ll:
- Move the whole “Now Playing” screen (which includes the mini-player) downwards (
- Make the album cover fit on the mini-player (a state animation)
We don’t want to animate everything off-screen because the mini-player should still be visible, so we move the top of the “Now Playing” screen to the height of the Tab Bar + the height of the mini-player.
scroll_now_playing.animate y: Screen.height - $.Tabs.height - Mini_Player.height + 1 borderRadius: topLeft: 0 topRight: 0 options: time: secondSetDuration curve: Spring(damping: 0.77)
(Apparently, we need to add
1 extra point to not have a small gap appear.)
We also get rid of the border radius because otherwise, we would have a mini-player with rounded corners.
Spring curve is only slightly bouncy, with a
damping instead of the default 0.5.
And we use this same spring curve when shrinking
$.Album_Cover to its
$.Album_Cover.animate "mini", time: secondSetDuration curve: Spring(damping: 0.77)
We did not include animation options when creating
”mini” (as we did for the
”paused” states), but we can add the desired duration and curve here.
Here’s a video of all eight animations at a tenth of their speed:
This last animation starts
0.5 seconds later because we want to be sure that the mini-player is in place before fading out the screen underneath it.
$.Now_Playing.animate opacity: 0 options: delay: 0.5 time: 0.5
(Here we’re animating the opacity of the
$.Now_Playing Sketch layer that’s inside our ScrollComponent.)
Now that you can see the mini-player’s transparency you’ll notice something is missing: Background Blur. Whatever is underneath the mini-player should be blurred.
Go back to Design, select the mini-player, give it a Blur of
25, and then change this blur from Layer to Background.
Ah, and now that we switched to the mini-player we can also “flip the switch”:
# The mini-player is now active miniPlayerActive = yes