Skip to content

Instantly share code, notes, and snippets.

@rgommezz
Last active August 6, 2018 18:29
Show Gist options
  • Save rgommezz/c1637fbcef7bfd792b814a68308e3ddf to your computer and use it in GitHub Desktop.
Save rgommezz/c1637fbcef7bfd792b814a68308e3ddf to your computer and use it in GitHub Desktop.
[...]
function runSpring({
clock,
from,
velocity,
toValue,
scrollEndDragVelocity,
snapOffset,
diffClampNode,
}) {
const state = {
finished: new Value(0),
velocity: new Value(0),
position: new Value(0),
time: new Value(0),
};
const config = {
damping: 1,
mass: 1,
stiffness: 50,
overshootClamping: true,
restSpeedThreshold: 0.001,
restDisplacementThreshold: 0.001,
toValue: new Value(0),
};
return [
cond(clockRunning(clock), 0, [
set(state.finished, 0),
set(state.velocity, velocity),
set(state.position, from),
set(config.toValue, toValue),
startClock(clock),
]),
spring(clock, state, config),
cond(state.finished, [
set(scrollEndDragVelocity, DRAG_END_INITIAL),
set(
snapOffset,
cond(
eq(toValue, 0),
// SnapOffset acts as an accumulator.
// We need to keep track of the previous offsets applied.
add(snapOffset, multiply(diffClampNode, -1)),
add(snapOffset, sub(NAV_BAR_HEIGHT, diffClampNode)),
),
),
stopClock(clock),
]),
state.position,
];
}
class CollapsibleNavBar extends React.Component {
constructor(props) {
super(props);
this.scrollY = new Value(0);
this.scrollEndDragVelocity = new Value(DRAG_END_INITIAL);
this.snapOffset = new Value(0);
const diffClampNode = diffClamp(
// snapOffset will compensate the value applied by snapping to avoid glitches
add(this.scrollY, this.snapOffset),
0,
NAV_BAR_HEIGHT,
);
const inverseDiffClampNode = multiply(diffClampNode, -1);
const clock = new Clock();
const snapPoint = cond(
lessThan(diffClampNode, NAV_BAR_HEIGHT / 2),
0,
-NAV_BAR_HEIGHT,
);
this.animatedNavBarTranslateY = cond(
// Condition to detect if we stopped scrolling
neq(this.scrollEndDragVelocity, DRAG_END_INITIAL),
runSpring({
clock,
from: inverseDiffClampNode,
velocity: 0,
toValue: snapPoint,
scrollEndDragVelocity: this.scrollEndDragVelocity,
snapOffset: this.snapOffset,
diffClampNode,
}),
inverseDiffClampNode,
);
this.animatedTitleOpacity = interpolate(this.animatedNavBarTranslateY, {
inputRange: [-NAV_BAR_HEIGHT, 0],
outputRange: [0, 1],
extrapolate: 'clamp',
});
}
render() {
return (
<View style={styles.container}>
<Animated.ScrollView
bounces={false}
scrollEventThrottle={1}
onScroll={event(
[
{
nativeEvent: {
contentOffset: {
y: this.scrollY,
},
},
},
],
{ useNativeDriver: true },
)}
onScrollEndDrag={event(
[
{
nativeEvent: {
velocity: {
y: this.scrollEndDragVelocity,
},
},
},
],
{ useNativeDriver: true },
)}
>
{Array.from({ length: 60 }).map((_, i) => (
<View key={i} style={styles.row}>
<Text>{i}</Text>
</View>
))}
</Animated.ScrollView>
<Animated.View
style={[
styles.navBar,
{
transform: [
{
translateY: this.animatedNavBarTranslateY,
},
],
},
]}
>
<Animated.Text
style={[styles.navBarTitle, { opacity: this.animatedTitleOpacity }]}
>
Navigation Bar
</Animated.Text>
</Animated.View>
</View>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment