react-native-reanimated#event TypeScript Examples
The following examples show how to use
react-native-reanimated#event.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: StickyItemFlatList.tsx From react-native-sticky-item with MIT License | 4 votes |
StickyItemFlatList = forwardRef( <T extends {}>(props: StickyItemFlatListProps<T>, ref: Ref<FlatList<T>>) => { const { initialScrollIndex = 0, decelerationRate = DEFAULT_DECELERATION_RATE, itemWidth, itemHeight, separatorSize = DEFAULT_SEPARATOR_SIZE, borderRadius = DEFAULT_BORDER_RADIUS, stickyItemActiveOpacity = DEFAULT_STICKY_ITEM_ACTIVE_OPACITY, stickyItemWidth, stickyItemHeight, stickyItemBackgroundColors, stickyItemContent, onStickyItemPress, isRTL = DEFAULT_IS_RTL, ItemSeparatorComponent = Separator, ...rest } = props; // refs const flatListRef = useRef<FlatList<T>>(null); const tapRef = useRef<TapGestureHandler>(null); //#region variables const itemWidthWithSeparator = useMemo( () => itemWidth + separatorSize, [itemWidth, separatorSize] ); const separatorProps = useMemo( () => ({ size: separatorSize, }), [separatorSize] ); //#endregion //#region styles const contentContainerStyle = useMemo( () => [ rest.contentContainerStyle, { paddingLeft: itemWidth + separatorSize * 2, paddingRight: separatorSize, }, ], [rest.contentContainerStyle, itemWidth, separatorSize] ); //#endregion //#region methods const getHitSlop = useCallback( isMinimized => { const verticalPosition = isMinimized ? -((itemHeight - stickyItemHeight) / 2) : 0; const startPosition = isMinimized ? 0 : -separatorSize; const endPosition = isMinimized ? -(SCREEN_WIDTH - stickyItemWidth) : -(SCREEN_WIDTH - separatorSize - itemWidth); return { top: verticalPosition, right: isRTL ? startPosition : endPosition, left: isRTL ? endPosition : startPosition, bottom: verticalPosition, }; }, [ itemWidth, itemHeight, stickyItemWidth, stickyItemHeight, separatorSize, isRTL, ] ); const getItemLayout = useCallback( (_, index) => { return { length: itemWidthWithSeparator, // sticky item + previous items width offset: itemWidthWithSeparator + itemWidthWithSeparator * index, index, }; }, [itemWidthWithSeparator] ); //#endregion //#region gesture const x = useValue(0); const tapState = useValue(State.UNDETERMINED); const tapGestures = useGestureHandler({ state: tapState }); const onScroll = event([ { nativeEvent: { contentOffset: { x, }, }, }, ]); const onScrollEnd = event([ { nativeEvent: { contentOffset: { x, }, }, }, ]); //#endregion //#region effects //@ts-ignore useImperativeHandle(ref, () => flatListRef.current!.getNode()); useCode( () => cond(eq(tapState, State.END), [ call([tapState], () => { if (onStickyItemPress) { onStickyItemPress(); } }), set(tapState, State.UNDETERMINED), ]), [tapState] ); useCode( () => onChange( x, call([x], args => { if (tapRef.current) { const isMinimized = args[0] > 0; // @ts-ignore tapRef.current.setNativeProps({ hitSlop: getHitSlop(isMinimized), }); } }) ), [ x, itemWidth, itemHeight, stickyItemWidth, stickyItemWidth, separatorSize, ] ); useEffect(() => { /** * @DEV * to fix stick item position with fast refresh */ x.setValue(0); if (tapRef.current) { // @ts-ignore tapRef.current.setNativeProps({ hitSlop: getHitSlop(initialScrollIndex !== 0), }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [getHitSlop]); //#endregion // render const renderSeparator = useCallback(() => { if (typeof ItemSeparatorComponent === 'function') { // @ts-ignore return ItemSeparatorComponent(separatorProps); } else { // @ts-ignore return <ItemSeparatorComponent size={separatorProps.size} />; } }, [ItemSeparatorComponent, separatorProps]); return ( <TapGestureHandler ref={tapRef} waitFor={flatListRef} shouldCancelWhenOutside={true} {...tapGestures} > <Animated.View> <AnimatedFlatList {...rest} ref={flatListRef} initialScrollIndex={initialScrollIndex} inverted={isRTL} ItemSeparatorComponent={renderSeparator} contentContainerStyle={contentContainerStyle} horizontal={true} showsHorizontalScrollIndicator={false} scrollEventThrottle={1} pagingEnabled={true} decelerationRate={decelerationRate} snapToAlignment={'start'} snapToInterval={itemWidth + separatorSize} onScroll={onScroll} onScrollAnimationEnd={onScrollEnd} getItemLayout={getItemLayout} /> <StickyItem x={x} tapState={tapState} itemWidth={itemWidth} itemHeight={itemHeight} separatorSize={separatorSize} borderRadius={borderRadius} stickyItemActiveOpacity={stickyItemActiveOpacity} stickyItemWidth={stickyItemWidth} stickyItemHeight={stickyItemHeight} stickyItemBackgroundColors={stickyItemBackgroundColors} stickyItemContent={stickyItemContent} isRTL={isRTL} /> </Animated.View> </TapGestureHandler> ); } )
Example #2
Source File: index.tsx From react-native-scroll-bottom-sheet with MIT License | 4 votes |
constructor(props: Props<T>) {
super(props);
const { initialSnapIndex, animationType } = props;
const animationDriver = animationType === 'timing' ? 0 : 1;
const animationDuration =
(props.animationType === 'timing' && props.animationConfig?.duration) ||
DEFAULT_ANIMATION_DURATION;
const ScrollComponent = this.getScrollComponent();
// @ts-ignore
this.scrollComponent = Animated.createAnimatedComponent(ScrollComponent);
const snapPoints = this.getNormalisedSnapPoints();
const openPosition = snapPoints[0];
const closedPosition = this.props.enableOverScroll
? windowHeight
: snapPoints[snapPoints.length - 1];
const initialSnap = snapPoints[initialSnapIndex];
this.nextSnapIndex = new Value(initialSnapIndex);
const initialDecelerationRate = Platform.select({
android:
props.initialSnapIndex === 0 ? ANDROID_NORMAL_DECELERATION_RATE : 0,
ios: IOS_NORMAL_DECELERATION_RATE,
});
this.decelerationRate = new Value(initialDecelerationRate);
const handleGestureState = new Value<GestureState>(-1);
const handleOldGestureState = new Value<GestureState>(-1);
const drawerGestureState = new Value<GestureState>(-1);
const drawerOldGestureState = new Value<GestureState>(-1);
const lastSnapInRange = new Value(1);
this.prevTranslateYOffset = new Value(initialSnap);
this.translationY = new Value(initialSnap);
this.lastSnap = new Value(initialSnap);
this.onHandleGestureEvent = event([
{
nativeEvent: {
translationY: this.dragY,
oldState: handleOldGestureState,
state: handleGestureState,
velocityY: this.velocityY,
},
},
]);
this.onDrawerGestureEvent = event([
{
nativeEvent: {
translationY: this.dragY,
oldState: drawerOldGestureState,
state: drawerGestureState,
velocityY: this.velocityY,
},
},
]);
this.onScrollBeginDrag = event([
{
nativeEvent: {
contentOffset: { y: this.lastStartScrollY },
},
},
]);
const didHandleGestureBegin = eq(handleGestureState, GestureState.ACTIVE);
const isAnimationInterrupted = and(
or(
eq(handleGestureState, GestureState.BEGAN),
eq(drawerGestureState, GestureState.BEGAN),
and(
eq(this.isAndroid, 0),
eq(animationDriver, 1),
or(
eq(drawerGestureState, GestureState.ACTIVE),
eq(handleGestureState, GestureState.ACTIVE)
)
)
),
clockRunning(this.animationClock)
);
this.didGestureFinish = or(
and(
eq(handleOldGestureState, GestureState.ACTIVE),
eq(handleGestureState, GestureState.END)
),
and(
eq(drawerOldGestureState, GestureState.ACTIVE),
eq(drawerGestureState, GestureState.END)
)
);
// Function that determines if the last snap point is in the range {snapPoints}
// In the case of interruptions in the middle of an animation, we'll get
// lastSnap values outside the range
const isLastSnapPointInRange = (i: number = 0): Animated.Node<number> =>
i === snapPoints.length
? lastSnapInRange
: cond(
eq(this.lastSnap, snapPoints[i]),
[set(lastSnapInRange, 1)],
isLastSnapPointInRange(i + 1)
);
const scrollY = [
set(lastSnapInRange, 0),
isLastSnapPointInRange(),
cond(
or(
didHandleGestureBegin,
and(
this.isManuallySetValue,
not(eq(this.manualYOffset, snapPoints[0]))
)
),
[set(this.dragWithHandle, 1), 0]
),
cond(
// This is to account for a continuous scroll on the drawer from a snap point
// Different than top, bringing the drawer to the top position, so that if we
// change scroll direction without releasing the gesture, it doesn't pull down the drawer again
and(
eq(this.dragWithHandle, 1),
greaterThan(snapPoints[0], add(this.lastSnap, this.dragY)),
and(not(eq(this.lastSnap, snapPoints[0])), lastSnapInRange)
),
[
set(this.lastSnap, snapPoints[0]),
set(this.dragWithHandle, 0),
this.lastStartScrollY,
],
cond(eq(this.dragWithHandle, 1), 0, this.lastStartScrollY)
),
];
this.didScrollUpAndPullDown = cond(
and(
greaterOrEq(this.dragY, this.lastStartScrollY),
greaterThan(this.lastStartScrollY, 0)
),
set(this.scrollUpAndPullDown, 1)
);
this.setTranslationY = cond(
and(
not(this.dragWithHandle),
not(greaterOrEq(this.dragY, this.lastStartScrollY))
),
set(this.translationY, sub(this.dragY, this.lastStartScrollY)),
set(this.translationY, this.dragY)
);
this.extraOffset = cond(
eq(this.scrollUpAndPullDown, 1),
this.lastStartScrollY,
0
);
const endOffsetY = add(
this.lastSnap,
this.translationY,
multiply(1 - props.friction, this.velocityY)
);
this.calculateNextSnapPoint = (i = 0): Animated.Node<number> | number =>
i === snapPoints.length
? this.tempDestSnapPoint
: cond(
greaterThan(
abs(sub(this.tempDestSnapPoint, endOffsetY)),
abs(sub(add(snapPoints[i], this.extraOffset), endOffsetY))
),
[
set(this.tempDestSnapPoint, add(snapPoints[i], this.extraOffset)),
set(this.nextSnapIndex, i),
this.calculateNextSnapPoint(i + 1),
],
this.calculateNextSnapPoint(i + 1)
);
const runAnimation = ({
clock,
from,
to,
position,
finished,
velocity,
frameTime,
}: TimingParams) => {
const state = {
finished,
velocity: new Value(0),
position,
time: new Value(0),
frameTime,
};
const timingConfig = {
duration: animationDuration,
easing:
(props.animationType === 'timing' && props.animationConfig?.easing) ||
DEFAULT_EASING,
toValue: new Value(0),
};
const springConfig = {
...DEFAULT_SPRING_PARAMS,
...((props.animationType === 'spring' && props.animationConfig) || {}),
toValue: new Value(0),
};
return [
cond(and(not(clockRunning(clock)), not(eq(finished, 1))), [
// If the clock isn't running, we reset all the animation params and start the clock
set(state.finished, 0),
set(state.velocity, velocity),
set(state.time, 0),
set(state.position, from),
set(state.frameTime, 0),
set(timingConfig.toValue, to),
set(springConfig.toValue, to),
startClock(clock),
]),
// We run the step here that is going to update position
cond(
eq(animationDriver, 0),
timing(clock, state, timingConfig),
spring(clock, state, springConfig)
),
cond(
state.finished,
[
call([this.nextSnapIndex], ([value]) => {
if (value !== this.prevSnapIndex) {
this.props.onSettle?.(value);
}
this.prevSnapIndex = value;
}),
// Resetting appropriate values
set(drawerOldGestureState, GestureState.END),
set(handleOldGestureState, GestureState.END),
set(this.prevTranslateYOffset, state.position),
cond(eq(this.scrollUpAndPullDown, 1), [
set(
this.prevTranslateYOffset,
sub(this.prevTranslateYOffset, this.lastStartScrollY)
),
set(this.lastStartScrollY, 0),
set(this.scrollUpAndPullDown, 0),
]),
cond(eq(this.destSnapPoint, snapPoints[0]), [
set(this.dragWithHandle, 0),
]),
set(this.isManuallySetValue, 0),
set(this.manualYOffset, 0),
stopClock(clock),
this.prevTranslateYOffset,
],
// We made the block return the updated position,
state.position
),
];
};
const translateYOffset = cond(
isAnimationInterrupted,
[
// set(prevTranslateYOffset, animationPosition) should only run if we are
// interrupting an animation when the drawer is currently in a different
// position than the top
cond(
or(
this.dragWithHandle,
greaterOrEq(abs(this.prevDragY), this.lastStartScrollY)
),
set(this.prevTranslateYOffset, this.animationPosition)
),
set(this.animationFinished, 1),
set(this.translationY, 0),
// Resetting appropriate values
set(drawerOldGestureState, GestureState.END),
set(handleOldGestureState, GestureState.END),
// By forcing that frameTime exceeds duration, it has the effect of stopping the animation
set(this.animationFrameTime, add(animationDuration, 1000)),
set(this.velocityY, 0),
stopClock(this.animationClock),
this.prevTranslateYOffset,
],
cond(
or(
this.didGestureFinish,
this.isManuallySetValue,
clockRunning(this.animationClock)
),
[
runAnimation({
clock: this.animationClock,
from: cond(
this.isManuallySetValue,
this.prevTranslateYOffset,
add(this.prevTranslateYOffset, this.translationY)
),
to: this.destSnapPoint,
position: this.animationPosition,
finished: this.animationFinished,
frameTime: this.animationFrameTime,
velocity: this.velocityY,
}),
],
[
set(this.animationFrameTime, 0),
set(this.animationFinished, 0),
// @ts-ignore
this.prevTranslateYOffset,
]
)
);
this.translateY = interpolate(
add(translateYOffset, this.dragY, multiply(scrollY, -1)),
{
inputRange: [openPosition, closedPosition],
outputRange: [openPosition, closedPosition],
extrapolate: Extrapolate.CLAMP,
}
);
this.position = interpolate(this.translateY, {
inputRange: [openPosition, snapPoints[snapPoints.length - 1]],
outputRange: [1, 0],
extrapolate: Extrapolate.CLAMP,
});
}