Skip to content

Instantly share code, notes, and snippets.

@kelleyvanevert
Created November 10, 2022 10:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kelleyvanevert/4c3b4d3f9218e22792b4c6891c80276f to your computer and use it in GitHub Desktop.
Save kelleyvanevert/4c3b4d3f9218e22792b4c6891c80276f to your computer and use it in GitHub Desktop.
React Native Reanimated
import React from "react";
import { View, StyleSheet, Dimensions } from "react-native";
import { darken } from "polished";
import Animated, {
useAnimatedStyle,
Extrapolate,
useSharedValue,
useAnimatedProps,
interpolate,
useAnimatedGestureHandler,
withSpring,
cancelAnimation,
runOnJS,
} from "react-native-reanimated";
import { PanGestureHandler } from "react-native-gesture-handler";
import AnimateableText from "react-native-animateable-text";
import { useRefCallback } from "@mywheels/common/util";
import { magic, theme } from "../../../ui";
type Props = {
initialValue: number;
onChange: (value: number) => void;
};
const range = [0, 99];
const size = 34;
export const MinScoreSlider = React.memo(
({ initialValue, onChange }: Props) => {
const isInitialized = useSharedValue(0);
const containerWidth = useSharedValue(Dimensions.get("window").width - 48);
const x = useSharedValue(0);
const _onChange = useRefCallback(onChange);
const cursorAnimStyle = useAnimatedStyle(() => {
return {
transform: [
{
translateX: x.value,
},
],
};
}, [x]);
const onPan = useAnimatedGestureHandler(
{
onStart() {
cancelAnimation(x);
},
onActive(e) {
x.value = Math.min(
containerWidth.value - size,
Math.max(0, e.x - size / 2)
);
},
onEnd(e) {
const endX = Math.min(
containerWidth.value - size,
Math.max(0, e.x - size / 2)
);
const newValue = Math.round(
interpolate(
endX,
[0, containerWidth.value - size],
range,
Extrapolate.CLAMP
)
);
x.value = withSpring(
interpolate(newValue, range, [0, containerWidth.value - size]),
magic
);
runOnJS(_onChange)(newValue);
},
},
[x]
);
const cursorLabelProps = useAnimatedProps(() => {
return {
text:
"≥ " +
Math.round(
interpolate(
x.value,
[0, containerWidth.value - size],
range,
Extrapolate.CLAMP
)
),
};
}, [x, containerWidth]);
return (
<PanGestureHandler maxPointers={1} minDist={0} onGestureEvent={onPan}>
<Animated.View
style={styles.container}
onLayout={(e) => {
const contWidth = e.nativeEvent.layout.width;
containerWidth.value = contWidth;
x.value = interpolate(initialValue, range, [
0,
containerWidth.value - size,
]);
isInitialized.value = 1;
}}
>
<View style={styles.line} />
<Animated.View style={[styles.cursor, cursorAnimStyle]}>
<AnimateableText
style={styles.value}
animatedProps={cursorLabelProps}
/>
<View style={styles.cursorBorder} />
</Animated.View>
</Animated.View>
</PanGestureHandler>
);
}
);
const styles = StyleSheet.create({
container: {
position: "relative",
height: size,
justifyContent: "center",
},
line: {
marginHorizontal: 8,
height: 8,
borderWidth: 1,
borderColor: theme.colors.gray200,
borderRadius: 2,
backgroundColor: theme.colors.gray100,
},
cursor: {
height: size,
width: size,
position: "absolute",
top: 0,
left: 0,
backgroundColor: theme.colors.yellow,
borderRadius: 3,
justifyContent: "center",
alignItems: "center",
},
cursorBorder: {
...StyleSheet.absoluteFillObject,
borderWidth: 2,
borderColor: darken(0.05, theme.colors.yellow),
borderRadius: 3,
},
value: {
color: "white",
fontWeight: "bold",
fontSize: 12,
lineHeight: 14,
height: 14,
padding: 0,
textAlign: "center",
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment