Skip to content
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

Supported Material Motion Transitions (Android) #714

Merged
merged 29 commits into from
Dec 10, 2023

Conversation

grahammendick
Copy link
Owner

@grahammendick grahammendick commented Aug 19, 2023

Material transitions help users understand and navigate an app. For example, shared axis is for UI elements that have a spatial or navigational relationship.

Configure them using the crumbStyle and unmountStyle props on the NavigationStack or Scene components.

<NavigationStack>
  <Scene 
    crumbStyle={from => from ? null : { type: 'sharedAxis' }}
    unmountStyle={from => from ? { type: 'sharedAxis' } : null}>

Transitions are different to custom animations because the Fragment is destroyed before the transition begins. Had to listen for the Transition to complete before popping from the React stack, for example, otherwise the unmounting scene would go blank.

Another complication was that Fresco (React Native image library) has a bug that meant images disappeared when a Fragment was detached. Had to fix React Native core before supporting Transitions. Will wait for that fix to make it into a React Native release before merging this PR.

Without this each child transitions independently - the toolbar separate to the scroll view, for example
The fragment is destroyed immediately. Android doesn't wait for the transitions to complete - unlike with animations. If React removes it then the content will disappear (unmount). So listened for the leaving transition to complete before unmounting
When the re/enter transitions end then call rest - equivalent to animation end, but for transitions. Need to call rest in pause too because if pressing very fast the end is called when the scene hasn't got a parent anymore. Pause caused first when it still has
They both need to call onRest
`unmountStyle={() => {type: 'sharedAxis'}}`
It threw an error when pressing very fast going forward with long duration transition - because the parent was an Overlay and not the NavigationStackView. Also it's not needed because if it's paused it means another transition has taken over so can let that one call rest. Only need the latest enter transition to call rest - previous ones in flight aren't relevant
Set the transition durations to seconds and then press the back arrow mid transition. Get an error - Android says the scene already has a parent, probably the overlay used for transition. So removed scene from parent before popping back
from https://github.com/material-components/material-components-android/blob/master/docs/theming/Motion.md#transitions
> prefer the MaterialContainerTransform(Context, boolean) constructor which loads theme-based values upfront so Hold or MaterialElevationScale’s duration can be accurately set using MaterialContainerTransform.getDuration
If there's an exit transition but no enter one then rest wasn't called. Rest was tied either to animation end or transition end. But exit transition only means no animations and no enter trans.
So checked for this and passed 0 animation so that it goes down the instant onRest call
Might want black underlay for animations and white underlay for transitions. Underlay color matching scene background works better for transitions because of the fade. Underlay color contrasting scene background works better for animations so scenes stand out
In Twitter sample, navigated A --> B then back to A. Then edited NavigationStack underlay color and navigated to B. This would give empty screen.
React Native reruns the App when editing the App.js which caused an empty navigation. Back the crumb was already on 1 so it tried to go back. And that removed the view and gave a blank screen. Not totally sure of the reason - but basically a few navigations happen when editing App.js then navigating.
Only removing the parent if not the stack solved it. This also still works for when fast navigating - reason this code was introduced. Since that only failed because tried to set parent when it was already the overlay because still animating
Already fixed for transitions but it can happen for animations to. Tried setting a slow transition forward then press back fast for the animation - not sure if it needed the slow transition? maybe because transitions don't block presses back think that animations do
Matches with getSharedElement(s)
Can render stack without scenes to start with so need to show the underlay color
Added props to the stack and scene native specs
@grahammendick grahammendick changed the title Supported Material Motion Transitions Supported Material Motion Transitions (Android) Nov 10, 2023
@grahammendick grahammendick merged commit f96fcef into master Dec 10, 2023
@grahammendick grahammendick deleted the material-transition branch December 10, 2023 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant