Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
updateHeaderOffset,
[
Animated.cond(
notBouncingAtTheTop,
[
// bouncing at the bottom,
// normally the header will be fully up at this point but sometimes
// the content is not tall enough to cause that, so we still need to
// update the header position just like above. The only difference is that
// when the bounce snaps back, we don't want to trigger opening the header
// like we do when the user explicitly scrolls back upward.
Animated.cond(
Animated.greaterThan(scrollDiff, 0),
[
// y offset got bigger so scrolling down (content travels up the screen)
Animated.set(
headerOffsetY,
Animated.max(negative(headerHeight), Animated.sub(headerOffsetY, scrollDiff))
),
],
[
// y offset got smaller so scrolling up (content travels down the screen)
Animated.cond(Animated.or(headerIsNotFullyUp, nearTheTop), [
Animated.set(headerOffsetY, Animated.min(0, Animated.sub(headerOffsetY, scrollDiff))),
]),
]
),
],
[
// bouncing at the top, keep the header fully open
Animated.set(headerOffsetY, 0),
// deref scroll diff to prevent diff buildup when ignoring changes
? A.cond(
A.clockRunning(oppositeClock),
A.stopClock(oppositeClock),
)
: 0,
// run our animation clock
A.cond(
A.clockRunning(clock),
// do nothing if our clock is already running
0,
// otherwise pre set all the values
[
// If the clock isn't running we reset all the animation params and start the clock
A.set(state.finished, 0),
A.set(state.time, 0),
A.set(state.position, value),
A.set(state.frameTime, 0),
A.set(config.toValue, dest),
A.startClock(clock),
],
),
// we run the step here that is going to update position
A.timing(clock, state, config),
// if the animation is over we stop the clock
A.cond(state.finished, A.block([A.stopClock(clock), onFinish])),
// we made the block return the updated position
A.set(value, state.position),
]);
};
// custom
value: A.Value,
dest: A.Adaptable,
// state
finished: A.Value,
position: A.Value,
time: A.Value,
frameTime: A.Value,
// config
toValue: A.Value,
) =>
A.block([
A.set(finished, 0),
A.set(time, 0),
A.set(position, value),
A.set(frameTime, 0),
A.set(toValue, dest),
]),
);
const runAnimation = getAnimationRunner(props);
const forwardAnimationClock = new A.Clock();
const backwardAnimationClock = new A.Clock();
const animation = A.block([
A.cond(
A.eq(animationState, AnimationState.PLAY_FORWARD),
// run all the forward animations
runAnimation(
{
clock: forwardAnimationClock,
oppositeClock: backwardAnimationClock,
value: masterValue,
dest: 1,
onFinish: A.set(animationState, AnimationState.END_POINT),
},
props,
),
// 0,
),
A.cond(
A.eq(animationState, AnimationState.PLAY_BACKWARD),
// run all the backward animations
runAnimation(
{
clock: backwardAnimationClock,
oppositeClock: forwardAnimationClock,
value: masterValue,
dest: 0,
onFinish: A.set(animationState, AnimationState.START_POINT),
},
// Some spring behaviour config:
damping: 7.5,
mass: 1.2,
stiffness: 121.6,
overshootClamping: true,
restSpeedThreshold: 0.001,
restDisplacementThreshold: 0.001,
};
return Animated.block([
// Reset state when we're starting the clock
Animated.cond(
Animated.not(Animated.clockRunning(clock)), [
Animated.set(state.finished, 0),
Animated.set(state.velocity, velocity),
Animated.set(state.position, value),
Animated.set(state.time, 0),
Animated.startClock(clock),
]
),
// Run the animation and stop the clock when we're done
Animated.spring(clock, state, config),
Animated.cond(state.finished, Animated.stopClock(clock)),
state.position
]);
};
tabIsActive,
[
// the tab just became active so we might need to adjust the scroll offset to avoid unwanted
// white space before allowing the scroll offset to affect the header position
Animated.cond(
Animated.greaterThan(Animated.multiply(-1, headerOffsetY), scrollOffsetY),
Animated.call([headerOffsetY], ([y]) => {
if (!flatListRef.current) {
throw new Error(
"Please make sure that tab content is wrapped with a StickyTabPageFlatList or a StickyTabPageScrollView"
)
}
flatListRef.current.getNode().scrollToOffset({ offset: -y, animated: false })
lockHeaderPosition.setValue(0)
}),
Animated.set(lockHeaderPosition, 0)
),
],
Animated.set(lockHeaderPosition, 1)
),
]),
[]
[
// If the clock isn't running we reset all the animation params and start the clock
A.set(state.finished, 0),
A.set(state.time, 0),
A.set(state.position, value),
A.set(state.frameTime, 0),
A.set(config.toValue, dest),
A.startClock(clock),
],
),
// we run the step here that is going to update position
A.timing(clock, state, config),
// if the animation is over we stop the clock
A.cond(state.finished, A.block([A.stopClock(clock), onFinish])),
// we made the block return the updated position
A.set(value, state.position),
]);
};
// the scrolling is going
const updateHeaderOffset = Animated.cond(
Animated.greaterThan(scrollDiff, 0),
[
// y offset got bigger so scrolling down (content travels up the screen)
// move the header up (hide it) unconditionally
Animated.set(amountScrolledUpward, 0),
Animated.set(headerOffsetY, Animated.max(negative(headerHeight), Animated.sub(headerOffsetY, scrollDiff))),
],
[
// y offset got smaller so scrolling up (content travels down the screen)
// if velocity is high enough or we're already moving the header up or we're near the top of the scroll view
// then move the header down (show it)
Animated.set(amountScrolledUpward, Animated.add(amountScrolledUpward, Animated.abs(scrollDiff))),
Animated.cond(Animated.or(upwardScrollThresholdBreached, headerIsNotFullyUp, nearTheTop), [
Animated.set(headerOffsetY, Animated.min(0, Animated.sub(headerOffsetY, scrollDiff))),
]),
]
)
// we don't want to manipulate the header position while bouncing at the top or the bottom of the scroll view
// cause it feels weeeird
const notBouncingAtTheTop = Animated.greaterThan(scrollOffsetY, 0)
const notBouncingAtTheBottom = Animated.lessThan(scrollOffsetY, Animated.sub(contentHeight, layoutHeight))
const updateHeaderOffsetWhenNotBouncing = Animated.cond(
Animated.and(notBouncingAtTheTop, notBouncingAtTheBottom),
updateHeaderOffset,
[
Animated.cond(
notBouncingAtTheTop,
[
A.stopClock(oppositeClock),
)
: 0,
// run our animation clock
A.cond(
A.clockRunning(clock),
// do nothing if our clock is already running
0,
// otherwise pre set all the values
[
// If the clock isn't running we reset all the animation params and start the clock
A.set(state.finished, 0),
A.set(state.time, 0),
A.set(state.position, value),
A.set(state.frameTime, 0),
A.set(config.toValue, dest),
A.startClock(clock),
],
),
// we run the step here that is going to update position
A.timing(clock, state, config),
// if the animation is over we stop the clock
A.cond(state.finished, A.block([A.stopClock(clock), onFinish])),
// we made the block return the updated position
A.set(value, state.position),
]);
};
cond(
isInRegion(x, y, LEFT),
set(command, Command.LEFT),
cond(
isInRegion(x, y, RIGHT),
set(command, Command.RIGHT),
cond(
isInRegion(x, y, CENTER),
set(command, Command.CENTER),
set(command, Command.UNDETERMINED)
)
)
)
)
),
set(state, State.UNDETERMINED)
])
]),
[command, state, x, y]