diff --git a/packages/stack/src/views/Stack/Card.tsx b/packages/stack/src/views/Stack/Card.tsx index 3712d649..cc3b8460 100755 --- a/packages/stack/src/views/Stack/Card.tsx +++ b/packages/stack/src/views/Stack/Card.tsx @@ -202,7 +202,11 @@ export default class Card extends React.Component { } if (closing !== prevProps.closing) { - this.isClosing.setValue(closing ? TRUE : FALSE); + // If the style updates during render, setting the value here doesn't work + // We need to defer it a bit so the animation starts properly + requestAnimationFrame(() => + this.isClosing.setValue(closing ? TRUE : FALSE) + ); } } @@ -267,6 +271,17 @@ export default class Card extends React.Component { finished: new Value(FALSE), }; + private handleTransitionEnd = () => { + this.isRunningAnimation = false; + this.interpolatedStyle = this.getInterpolatedStyle( + this.props.styleInterpolator, + this.props.index, + this.props.current, + this.props.next, + this.props.layout + ); + }; + private runTransition = (isVisible: Binary | Animated.Node) => { const { open: openingSpec, close: closingSpec } = this.props.transitionSpec; @@ -331,7 +346,9 @@ export default class Card extends React.Component { call([this.isVisible], ([value]: ReadonlyArray) => { const isOpen = Boolean(value); const { onOpen, onClose } = this.props; - this.isRunningAnimation = false; + + this.handleTransitionEnd(); + if (isOpen) { onOpen(true); } else { @@ -357,7 +374,7 @@ export default class Card extends React.Component { cond(neq(this.nextIsVisible, UNSET), [ // Stop any running animations cond(clockRunning(this.clock), [ - call([], () => (this.isRunningAnimation = false)), + call([], this.handleTransitionEnd), stopClock(this.clock), ]), set(this.gesture, 0), @@ -511,6 +528,18 @@ export default class Card extends React.Component { }) ); + // Keep track of the style in a property to avoid changing the animated node when deps change + // The style shouldn't change in the middle of the animation and should refer to what was there at the start of it + // Which will be the last value when just before the render which started the animation + // We need to make sure to update this when the running animation ends + private interpolatedStyle = this.getInterpolatedStyle( + this.props.styleInterpolator, + this.props.index, + this.props.current, + this.props.next, + this.props.layout + ); + private gestureActivationCriteria() { const { layout, gestureDirection, gestureResponseDistance } = this.props; @@ -551,35 +580,39 @@ export default class Card extends React.Component { render() { const { - index, active, transparent, - layout, + styleInterpolator, + index, current, next, + layout, overlayEnabled, shadowEnabled, gestureEnabled, gestureDirection, children, - styleInterpolator, containerStyle: customContainerStyle, contentStyle, ...rest } = this.props; + if (!this.isRunningAnimation) { + this.interpolatedStyle = this.getInterpolatedStyle( + styleInterpolator, + index, + current, + next, + layout + ); + } + const { containerStyle, cardStyle, overlayStyle, shadowStyle, - } = this.getInterpolatedStyle( - styleInterpolator, - index, - current, - next, - layout - ); + } = this.interpolatedStyle; const handleGestureEvent = gestureEnabled ? gestureDirection === 'vertical' diff --git a/packages/stack/src/views/Stack/Stack.tsx b/packages/stack/src/views/Stack/Stack.tsx index efb29d48..ab43ed4e 100755 --- a/packages/stack/src/views/Stack/Stack.tsx +++ b/packages/stack/src/views/Stack/Stack.tsx @@ -167,11 +167,14 @@ export default class Stack extends React.Component { : undefined; const next = nextRoute ? progress[nextRoute.key] : undefined; + const oldScene = state.scenes[index]; const scene = { route, previous: previousRoute, descriptor: - props.descriptors[route.key] || state.descriptors[route.key], + props.descriptors[route.key] || + state.descriptors[route.key] || + (oldScene ? oldScene.descriptor : { options: {} }), progress: { current, next, @@ -179,8 +182,6 @@ export default class Stack extends React.Component { }, }; - const oldScene = state.scenes[index]; - if ( oldScene && scene.route === oldScene.route &&