Skip to content
This repository was archived by the owner on Feb 25, 2020. It is now read-only.

Commit

Permalink
fix: send events even is stack animation is vain (#270)
Browse files Browse the repository at this point in the history
  • Loading branch information
osdnk authored Oct 22, 2019
1 parent cb8c772 commit 3d4b173
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 89 deletions.
35 changes: 34 additions & 1 deletion example/src/ModalStack.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import * as React from 'react';
import { Button, View, Text, Dimensions, Switch } from 'react-native';
import {
Button,
View,
Text,
Dimensions,
Switch,
TextInput,
} from 'react-native';
import {
createStackNavigator,
CardStyleInterpolators,
Expand Down Expand Up @@ -127,6 +134,10 @@ class DetailsScreen extends React.Component<NavigationStackScreenProps> {
title="Go to Details... again"
onPress={() => this.props.navigation.push('Details')}
/>
<Button
title="Go to inputs..."
onPress={() => this.props.navigation.push('Inputs')}
/>
<Button
title="Go to List"
onPress={() => this.props.navigation.navigate('List')}
Expand All @@ -143,12 +154,34 @@ class DetailsScreen extends React.Component<NavigationStackScreenProps> {
);
}
}
function InputsScreen({ navigation }: NavigationStackScreenProps) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Inputs Screen</Text>
<TextInput
defaultValue="sample"
autoFocus
style={{ backgroundColor: 'blue' }}
/>
<TextInput defaultValue="sample" style={{ backgroundColor: 'red' }} />
<TextInput defaultValue="sample" style={{ backgroundColor: 'green' }} />
<Button
title="Go to inputs... again"
onPress={() => navigation.push('Inputs')}
/>
</View>
);
}

export default createStackNavigator(
{
List: ListScreen,
Details: DetailsScreen,
Modal: Modal,
Inputs: {
screen: InputsScreen,
navigationOptions: { gestureDirection: 'vertical' },
},
},
{
initialRouteName: 'List',
Expand Down
206 changes: 118 additions & 88 deletions src/views/Stack/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ export default class Card extends React.Component<Props> {
private offset = new Value(0);
private velocityUntraversed = new Value(0);
private velocity = new Value(0);
private didMovementHappen = new Value(0);

private gestureState = new Value(0);

Expand Down Expand Up @@ -404,98 +405,126 @@ export default class Card extends React.Component<Props> {
private runTransition = (isVisible: Binary | Animated.Node<number>) => {
const { open: openingSpec, close: closingSpec } = this.props.transitionSpec;

return cond(eq(this.props.current, isVisible), NOOP_NODE, [
cond(clockRunning(this.clock), NOOP_NODE, [
// Animation wasn't running before
// Set the initial values and start the clock
set(this.toValue, isVisible),
// The velocity value is ideal for translating the whole screen
// But since we have 0-1 scale, we need to adjust the velocity
set(
this.transitionVelocity,
multiply(
cond(
this.distance,
divide(this.velocity, this.distance),
FALSE_NODE
),
-1
)
),
set(this.frameTime, FALSE_NODE),
set(this.transitionState.time, FALSE_NODE),
set(this.transitionState.finished, FALSE_NODE),
set(this.isVisible, isVisible),
startClock(this.clock),
call([this.isVisible], ([value]: ReadonlyArray<Binary>) => {
this.handleStartInteraction();

const { onTransitionStart } = this.props;
this.noAnimationStartedSoFar = false;
this.isRunningAnimation = true;
onTransitionStart && onTransitionStart({ closing: !value });
}),
]),
return [
cond(
eq(isVisible, TRUE_NODE),
openingSpec.animation === 'spring'
? memoizedSpring(
this.clock,
{ ...this.transitionState, velocity: this.transitionVelocity },
// @ts-ignore
{
...(this.openingSpecConfig as AnimatedSpringConfig),
toValue: this.toValue,
}
)
: timing(
this.clock,
{ ...this.transitionState, frameTime: this.frameTime },
{
...(this.openingSpecConfig as AnimatedTimingConfig),
toValue: this.toValue,
}
eq(this.props.current, isVisible),
call(
[this.didMovementHappen, this.isVisible],
([didMovementHappen]: ReadonlyArray<Binary>) => {
if (didMovementHappen) {
// if we go back to the same position,
// let's pretend that whole animation happen
// for making the logic consistent
// It's especially vital for having inputs properly focused.
this.handleStartInteraction();
const { onTransitionStart } = this.props;
onTransitionStart && onTransitionStart({ closing: true });
this.handleTransitionEnd();
this.props.onOpen(true);
}
}
),
[
cond(clockRunning(this.clock), NOOP_NODE, [
// Animation wasn't running before
// Set the initial values and start the clock
set(this.toValue, isVisible),
// The velocity value is ideal for translating the whole screen
// But since we have 0-1 scale, we need to adjust the velocity
set(
this.transitionVelocity,
multiply(
cond(
this.distance,
divide(this.velocity, this.distance),
FALSE_NODE
),
-1
)
),
closingSpec.animation === 'spring'
? memoizedSpring(
this.clock,
{ ...this.transitionState, velocity: this.transitionVelocity },
// @ts-ignore
{
...(this.closingSpecConfig as AnimatedSpringConfig),
toValue: this.toValue,
}
)
: timing(
this.clock,
{ ...this.transitionState, frameTime: this.frameTime },
{
...(this.closingSpecConfig as AnimatedTimingConfig),
toValue: this.toValue,
set(this.frameTime, FALSE_NODE),
set(this.transitionState.time, FALSE_NODE),
set(this.transitionState.finished, FALSE_NODE),
set(this.isVisible, isVisible),
startClock(this.clock),
call([this.isVisible], ([value]: ReadonlyArray<Binary>) => {
this.handleStartInteraction();

const { onTransitionStart } = this.props;
this.noAnimationStartedSoFar = false;
this.isRunningAnimation = true;
onTransitionStart && onTransitionStart({ closing: !value });
}),
]),
cond(
eq(isVisible, TRUE_NODE),
openingSpec.animation === 'spring'
? memoizedSpring(
this.clock,
{
...this.transitionState,
velocity: this.transitionVelocity,
},
// @ts-ignore
{
...(this.openingSpecConfig as AnimatedSpringConfig),
toValue: this.toValue,
}
)
: timing(
this.clock,
{ ...this.transitionState, frameTime: this.frameTime },
{
...(this.openingSpecConfig as AnimatedTimingConfig),
toValue: this.toValue,
}
),
closingSpec.animation === 'spring'
? memoizedSpring(
this.clock,
{
...this.transitionState,
velocity: this.transitionVelocity,
},
// @ts-ignore
{
...(this.closingSpecConfig as AnimatedSpringConfig),
toValue: this.toValue,
}
)
: timing(
this.clock,
{ ...this.transitionState, frameTime: this.frameTime },
{
...(this.closingSpecConfig as AnimatedTimingConfig),
toValue: this.toValue,
}
)
),
cond(this.transitionState.finished, [
// Reset values
set(this.isSwipeGesture, FALSE_NODE),
set(this.gesture, FALSE_NODE),
set(this.velocity, FALSE_NODE),
// When the animation finishes, stop the clock
stopClock(this.clock),
call([this.isVisible], ([value]: ReadonlyArray<Binary>) => {
const isOpen = Boolean(value);
const { onOpen, onClose } = this.props;

this.handleTransitionEnd();

if (isOpen) {
onOpen(true);
} else {
onClose(true);
}
)
}),
]),
]
),
cond(this.transitionState.finished, [
// Reset values
set(this.isSwipeGesture, FALSE_NODE),
set(this.gesture, FALSE_NODE),
set(this.velocity, FALSE_NODE),
// When the animation finishes, stop the clock
stopClock(this.clock),
call([this.isVisible], ([value]: ReadonlyArray<Binary>) => {
const isOpen = Boolean(value);
const { onOpen, onClose } = this.props;

this.handleTransitionEnd();

if (isOpen) {
onOpen(true);
} else {
onClose(true);
}
}),
]),
]);
set(this.didMovementHappen, 0),
];
};

private extrapolatedPosition = add(
Expand Down Expand Up @@ -576,6 +605,7 @@ export default class Card extends React.Component<Props> {
}
)
),
onChange(this.gestureUntraversed, set(this.didMovementHappen, 1)),
cond(
eq(this.gestureState, GestureState.ACTIVE),
[
Expand Down

0 comments on commit 3d4b173

Please sign in to comment.