Skip to content

Feat/new pan view improve animations #1574

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

Merged
merged 7 commits into from
Oct 8, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion generatedTypes/src/incubator/TransitionView/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { PropsWithChildren } from 'react';
import { ViewProps } from '../../components/view';
import { ForwardRefInjectedProps } from '../../commons/new';
import { Direction } from './useHiddenLocation';
import { Direction } from '../hooks/useHiddenLocation';
import { TransitionViewAnimationType } from './useAnimationEndNotifier';
import { AnimatedTransitionProps } from './useAnimatedTransition';
export { Direction, TransitionViewAnimationType };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Direction, HiddenLocation } from './useHiddenLocation';
import { Direction, HiddenLocation } from '../hooks/useHiddenLocation';
import { AnimationNotifierEndProps } from './useAnimationEndNotifier';
export interface AnimatedTransitionProps extends AnimationNotifierEndProps {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Direction } from './useHiddenLocation';
import { Direction } from '../hooks/useHiddenLocation';
export interface TranslatorProps {
initialVisibility: boolean;
}
Expand Down
2 changes: 1 addition & 1 deletion src/incubator/TransitionView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {View as RNView, LayoutChangeEvent} from 'react-native';
import Animated from 'react-native-reanimated';
import View, {ViewProps} from '../../components/view';
import {forwardRef, ForwardRefInjectedProps} from '../../commons/new';
import useHiddenLocation, {Direction} from './useHiddenLocation';
import useHiddenLocation, {Direction} from '../hooks/useHiddenLocation';
import {TransitionViewAnimationType} from './useAnimationEndNotifier';
import useAnimatedTransition, {AnimatedTransitionProps} from './useAnimatedTransition';
const AnimatedView = Animated.createAnimatedComponent(View);
Expand Down
2 changes: 1 addition & 1 deletion src/incubator/TransitionView/useAnimatedTransition.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable react-hooks/exhaustive-deps */
import {useEffect, useCallback} from 'react';
import {Direction, HiddenLocation} from './useHiddenLocation';
import {Direction, HiddenLocation} from '../hooks/useHiddenLocation';
import useAnimatedTranslator from './useAnimatedTranslator';
import useAnimationEndNotifier, {AnimationNotifierEndProps} from './useAnimationEndNotifier';

Expand Down
2 changes: 1 addition & 1 deletion src/incubator/TransitionView/useAnimatedTranslator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useCallback} from 'react';
import {useSharedValue, useAnimatedStyle, withSpring, withTiming} from 'react-native-reanimated';
import {Direction} from './useHiddenLocation';
import {Direction} from '../hooks/useHiddenLocation';

export interface TranslatorProps {
initialVisibility: boolean;
Expand Down
56 changes: 26 additions & 30 deletions src/incubator/panView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {isEmpty} from 'lodash';
import React, {useCallback} from 'react';
import {StyleProp, ViewStyle} from 'react-native';
import {StyleProp, View as RNView, ViewStyle} from 'react-native';
import {PanGestureHandler, PanGestureHandlerEventPayload} from 'react-native-gesture-handler';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
withTiming,
useAnimatedGestureHandler,
runOnJS
} from 'react-native-reanimated';
import {asBaseComponent} from '../../commons/new';
import {Constants} from '../../helpers';
import View, {ViewProps} from '../../components/view';
import {
PanViewDirections,
Expand All @@ -20,6 +20,7 @@ import {
getDismissVelocity,
DEFAULT_THRESHOLD
} from './panningUtil';
import useHiddenLocation from '../hooks/useHiddenLocation';
export {PanViewDirections, PanViewDismissThreshold};

export interface PanViewProps extends ViewProps {
Expand Down Expand Up @@ -64,7 +65,7 @@ const PanView = (props: Props) => {
const {
directions = [PanViewDirections.UP, PanViewDirections.DOWN, PanViewDirections.LEFT, PanViewDirections.RIGHT],
dismissible,
springBack,
springBack: propsSpringBack,
onDismiss,
directionLock,
threshold,
Expand All @@ -82,6 +83,9 @@ const PanView = (props: Props) => {
};
}, []);

const containerRef = React.createRef<RNView>();
const {onLayout, hiddenLocation} = useHiddenLocation({containerRef});

const getTranslationOptions = () => {
'worklet';
return {
Expand All @@ -105,27 +109,17 @@ const PanView = (props: Props) => {
runOnJS(onDismiss)();
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[onDismiss]);

const shouldDismissX = useCallback((isFinished: boolean) => {
'worklet';
dismiss(isFinished);
},
[dismiss]);

const shouldDismissY = useCallback((isFinished: boolean) => {
const springBack = useCallback(() => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here regarding the name...
Also why create a method with a similar name to a prop? Don't you find it confusing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do find it confusing, any suggestion?

Copy link
Collaborator

@ethanshar ethanshar Oct 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

animateToOrigin
animateToInitialPosition

anything that I can read and make sense without diving into the function implementation (:

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

animateToOrigin sounds like a good suggestion to replace animateToStart :)
But calling the function animateToInitialPosition and not animateToOrigin will sound unnatural and forced, don't you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

animateToOrigin sounds like a good suggestion to replace animateToStart :)

I agree

But calling the function animateToInitialPosition and not animateToOrigin will sound unnatural and forced, don't you think?

Maybe we can have a slight difference in the name, something like animateTargetToOrigin, returnToOrigin, resetToOrigin

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

'worklet';
dismiss(isFinished);
},
[dismiss]);

const springBackIfNeeded = useCallback(() => {
'worklet';
if (springBack) {
if (propsSpringBack) {
translationX.value = withSpring(0, SPRING_BACK_ANIMATION_CONFIG);
translationY.value = withSpring(0, SPRING_BACK_ANIMATION_CONFIG);
}
}, [springBack]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [propsSpringBack]);

const onGestureEvent = useAnimatedGestureHandler({
onStart: (_event: PanGestureHandlerEventPayload, context: {initialTranslation: Frame}) => {
Expand All @@ -139,28 +133,30 @@ const PanView = (props: Props) => {
const velocity = getDismissVelocity(event, directions, getTranslationOptions(), threshold);
if (velocity) {
waitingForDismiss.value = true;
if (velocity.x !== 0) {
const toX = Math.sign(translationX.value) * (Math.abs(translationX.value) + Constants.screenWidth);
translationX.value = withSpring(toX, {velocity: velocity.x, damping: 50}, shouldDismissX);
if (translationX.value !== 0 && velocity.x !== undefined && velocity.x !== 0) {
const toX = velocity.x > 0 ? hiddenLocation.right : hiddenLocation.left;
const duration = Math.abs((toX - translationX.value) / velocity.x) * 1000;
translationX.value = withTiming(toX, {duration}, dismiss);
}
if (velocity.y !== 0) {
const toY = Math.sign(translationY.value) * (Math.abs(translationY.value) + Constants.screenHeight);
translationY.value = withSpring(toY, {velocity: velocity.y, damping: 50}, shouldDismissY);

if (translationY.value !== 0 && velocity.y !== undefined && velocity.y !== 0) {
const toY = velocity.y > 0 ? hiddenLocation.bottom : hiddenLocation.top;
const duration = Math.abs((toY - translationY.value) / velocity.y) * 1000;
translationY.value = withTiming(toY, {duration}, dismiss);
}
} else {
springBackIfNeeded();
springBack();
}
} else {
springBackIfNeeded();
springBack();
}
}
},
[directions, dismissible, setTranslation, springBackIfNeeded]);
[directions, dismissible, setTranslation, springBack]);

return (
// TODO: delete comments once completed
// <View ref={containerRef} style={containerStyle} onLayout={onLayout}>
<View style={containerStyle}>
<RNView ref={containerRef} style={containerStyle} onLayout={onLayout}>
<PanGestureHandler onGestureEvent={isEmpty(directions) ? undefined : onGestureEvent}>
<Animated.View
// !visible.current && styles.hidden is done to fix a bug is iOS
Expand All @@ -171,7 +167,7 @@ const PanView = (props: Props) => {
<View {...others}>{children}</View>
</Animated.View>
</PanGestureHandler>
</View>
</RNView>
);
};

Expand Down