Improve slider animation performance
This commit is contained in:
parent
79975710e4
commit
497e631510
|
@ -1,11 +1,11 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { View, StyleProp, ViewStyle } from 'react-native';
|
import { View, StyleProp, ViewStyle } from 'react-native';
|
||||||
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
||||||
import Touchable from 'react-native-platform-touchable';
|
import Animated, { useSharedValue, useAnimatedStyle, interpolate, withTiming } from 'react-native-reanimated';
|
||||||
import Animated, { useSharedValue, useAnimatedStyle, interpolate } from 'react-native-reanimated';
|
|
||||||
|
|
||||||
import styles, { SLIDER_THUMB_RADIUS } from '../../styles';
|
import styles, { SLIDER_THUMB_RADIUS } from '../../styles';
|
||||||
import { useTheme } from '../../../../theme';
|
import { useTheme } from '../../../../theme';
|
||||||
|
// import { debounce } from '../../../../lib/methods/helpers';
|
||||||
|
|
||||||
interface ISliderProps {
|
interface ISliderProps {
|
||||||
value: number;
|
value: number;
|
||||||
|
@ -32,14 +32,15 @@ const Slider = React.memo(
|
||||||
}: ISliderProps) => {
|
}: ISliderProps) => {
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const [sliderWidth, setSliderWidth] = useState<number>(0);
|
const [sliderWidth, setSliderWidth] = useState<number>(0);
|
||||||
const position = useSharedValue(0);
|
const [isSliding, setSliding] = useState<boolean>(false);
|
||||||
|
const sliderThumbWidth = useSharedValue(2 * SLIDER_THUMB_RADIUS);
|
||||||
const currentValue = useSharedValue(0);
|
const currentValue = useSharedValue(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (value !== currentValue.value) {
|
if (!isSliding) {
|
||||||
currentValue.value = value;
|
currentValue.value = value;
|
||||||
}
|
}
|
||||||
}, [value]);
|
}, [value, isSliding]);
|
||||||
|
|
||||||
const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);
|
const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);
|
||||||
|
|
||||||
|
@ -49,20 +50,30 @@ const Slider = React.memo(
|
||||||
setSliderWidth(event.nativeEvent.layout.width);
|
setSliderWidth(event.nativeEvent.layout.width);
|
||||||
};
|
};
|
||||||
|
|
||||||
const tapGesture = Gesture.Tap().onStart(e => {
|
// const debouncedOnValueChange = debounce((value: number) => onValueChange(value), 50);
|
||||||
position.value = clamp(e.x, 0, sliderWidth);
|
|
||||||
currentValue.value = equivalentValue(position.value);
|
const tapGesture = Gesture.Tap()
|
||||||
onValueChange(currentValue.value);
|
.hitSlop({ vertical: 10 })
|
||||||
|
.onStart(e => {
|
||||||
|
currentValue.value = equivalentValue(clamp(e.x, 0, sliderWidth));
|
||||||
|
onValueChange(equivalentValue(clamp(e.x, 0, sliderWidth)));
|
||||||
});
|
});
|
||||||
|
|
||||||
const dragGesture = Gesture.Pan()
|
const dragGesture = Gesture.Pan()
|
||||||
.onChange(e => {
|
.hitSlop({ horizontal: 5, vertical: 20 })
|
||||||
position.value = clamp(e.x, 0, sliderWidth);
|
.onStart(() => {
|
||||||
currentValue.value = equivalentValue(position.value);
|
setSliding(true);
|
||||||
onValueChange(currentValue.value);
|
sliderThumbWidth.value = withTiming(3 * SLIDER_THUMB_RADIUS, { duration: 100 });
|
||||||
})
|
})
|
||||||
.onEnd(() => {
|
.onChange(e => {
|
||||||
onValueChange(currentValue.value);
|
currentValue.value = equivalentValue(clamp(e.x, 0, sliderWidth));
|
||||||
|
onValueChange(equivalentValue(clamp(e.x, 0, sliderWidth)));
|
||||||
|
})
|
||||||
|
.onEnd(e => {
|
||||||
|
sliderThumbWidth.value = withTiming(2 * SLIDER_THUMB_RADIUS, { duration: 100 });
|
||||||
|
currentValue.value = equivalentValue(clamp(e.x, 0, sliderWidth));
|
||||||
|
onValueChange(equivalentValue(clamp(e.x, 0, sliderWidth)));
|
||||||
|
setSliding(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
const animatedThumbStyles = useAnimatedStyle(() => ({
|
const animatedThumbStyles = useAnimatedStyle(() => ({
|
||||||
|
@ -70,7 +81,9 @@ const Slider = React.memo(
|
||||||
{
|
{
|
||||||
translateX: interpolate(currentValue.value, [0, maximumValue], [0, sliderWidth]) - SLIDER_THUMB_RADIUS
|
translateX: interpolate(currentValue.value, [0, maximumValue], [0, sliderWidth]) - SLIDER_THUMB_RADIUS
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
width: sliderThumbWidth.value,
|
||||||
|
height: sliderThumbWidth.value
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const animatedTrackStyles = useAnimatedStyle(() => ({
|
const animatedTrackStyles = useAnimatedStyle(() => ({
|
||||||
|
@ -81,11 +94,8 @@ const Slider = React.memo(
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.sliderContainer, containerStyle]}>
|
<View style={[styles.sliderContainer, containerStyle]}>
|
||||||
<Touchable onPress={() => {}}>
|
|
||||||
<GestureDetector gesture={gesture}>
|
<GestureDetector gesture={gesture}>
|
||||||
<View
|
<View style={[styles.track, { backgroundColor: maximumTrackTintColor || colors.buttonBackground }]} onLayout={onLayout}>
|
||||||
style={[styles.track, { backgroundColor: maximumTrackTintColor || colors.buttonBackground }]}
|
|
||||||
onLayout={onLayout}>
|
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={[styles.sliderThumb, { backgroundColor: thumbTintColor || colors.tintColor }, animatedThumbStyles]}
|
style={[styles.sliderThumb, { backgroundColor: thumbTintColor || colors.tintColor }, animatedThumbStyles]}
|
||||||
/>
|
/>
|
||||||
|
@ -94,7 +104,6 @@ const Slider = React.memo(
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</GestureDetector>
|
</GestureDetector>
|
||||||
</Touchable>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue