feat(menu): swipe to minimize the full-screen tip card - #1318
Merged
Conversation
Full screen on the "You" tab could only be left through the Close row. The expansion is now one 0..1 progress rather than a boolean: card size, its travel out of the slot, the page fading beneath it and the Close row all read the same value, so a drag can park the transition part-way through and hand it back where it found it. Every reader takes the progress inside a graphicsLayer lambda, so a drag redraws rather than recomposing the page. A release settles on the spring iOS already uses for this transition (response 0.45, damping fraction 0.85), carrying the gesture's velocity into it. Uncapped, the hardest flick sailed about 18% of the travel past the resting end, which lifts the card clear out of its slot and up under the status bar. Capping the carried velocity holds that to 5.6%, roughly 10dp, without flattening the bounce into a cut. TipCardOvershootTest drives the animation a frame at a time off a BroadcastFrameClock and holds both bounds: some bounce, and not much. The "Full Screen" caption is a later sibling than the card, so it paints on top of it while the growing card travels down across its slot. It now fades out over the first 8% of the expansion, ahead of the card reaching that spot at around 11%. One gap: the tab bar still switches on the committed intent rather than tracking the drag, because HideTabBar is boolean rather than progress-driven.
The Android swipe was ours, not a port: the gesture sat on the card, it took half the travel to close, and pushing an expanded card down did nothing. iOS PR #639 settled all three differently. Bringing them across: - Attach the drag to the page, not the card. Expanded, the card is 302dp of a wider display, so a pull that lands in the margin missed entirely. Nothing scrolls while the card is up, so there is no scroll to contend with. - Close at 0.3 of the travel rather than halfway. - Give the card 0.25 resistance when it is pushed down past full screen, and return it on the shorter spring iOS uses for a pull that fell short (response 0.3, so stiffness 439). - Hand back the touch slop the recogniser swallowed on the first delta, so the card starts where the finger did instead of jumping the slop distance. Two divergences stay. The settle still carries a capped release velocity, because Android has a swipe where iOS only has a tap and so has no velocity to carry. The page content still fades on progress rather than on the boolean, because our card is opaque at this call site and a boolean fade shows through a translucent one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Full screen on the "You" tab could only be left through the Close row, so this adds the swipe back down.
How it works
The expansion is one
0..1progress rather than a boolean. Card size, its travel out of the slot, the page fading beneath it and the Close row all read the same value, so a drag can park the transition part-way through and hand it back where it found it. Tap still drives the same progress to an end with a spring.Every reader takes the progress inside a
graphicsLayerlambda, so a drag redraws rather than recomposing the page.Settling a flick
A release settles on the spring iOS already uses for this transition (
response: 0.45, dampingFraction: 0.85), carrying the gesture's velocity into it. That velocity is what produces the overshoot, not the damping ratio, and iOS never hits it becauseYouScreenhas no drag gesture: its spring always starts from a standstill, where this damping ratio overshoots half a percent.Uncapped, the hardest flick sailed about 18% of the travel past the resting end, lifting the card clear out of its slot and up under the status bar. Capping the carried velocity holds it to 5.6%, roughly 10dp:
TipCardOvershootTestdrives the animation a frame at a time off aBroadcastFrameClock, so those are the values the card is drawn at rather than where the animation was aimed. It holds both bounds — the bounce has to be there, and it has to be small — measured from every tenth of the travel, since where a flick is released changes how far it carries past.The "Full Screen" caption
The caption is a later sibling than the card, so it paints on top of it while the growing card travels down across its slot: about 224dp of travel per unit of progress against 24dp of clearance. Faded over the whole expansion it stayed legible at the point it ended up printed across the card's face. It now fades over the first 8% of the progress, ahead of the card arriving at around 11%.
Known gap
The tab bar still switches on the committed intent rather than tracking the drag —
HideTabBaris boolean/counted, not progress-driven. Making it follow the progress is a separate change.