Created
August 5, 2022 08:37
-
-
Save dilipsuthar97/83eb3bbe6c1c8eef1af5c188d1e12900 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// --------------- LIBRARIES --------------- | |
import React, { memo } from 'react'; | |
import { View, Animated, StyleSheet, Easing, PanResponder } from 'react-native'; | |
// --------------- ASSETS --------------- | |
export const TRACK_HEIGHT = 32; | |
export const HOR_PAD = 10; | |
const Colors = { | |
OVERLAY_LIGHT_30: 'rgba(255,255,255,0.3)', | |
OVERLAY_LIGHT_40: 'rgba(255,255,255,0.4)', | |
OVERLAY_LIGHT_70: 'rgba(255,255,255,0.7)', | |
TRANSPARENT: 'rgba(0,0,0,0.0)', | |
PRIMARY: 'rgb(252, 70, 119)' | |
} | |
const SeekBar = React.forwardRef((props, ref) => { | |
// --------------- VARS --------------- | |
const progress = React.useRef(new Animated.Value(0)).current; | |
/** | |
* To remove stale closure effect we have used useRef hook to store value | |
* because state and normal var values will not updated inside stale closure effect. | |
* Learn more about stale closure here: | |
* https://dmitripavlutin.com/react-hooks-stale-closures/ | |
*/ | |
const isFullScreen = React.useRef(props.isFullScreen); | |
const seekbarWidth = React.useRef(0); | |
const progressWidth = progress.interpolate({ | |
inputRange: [0, 1], | |
outputRange: ['0%', '100%'], | |
extrapolate: 'clamp', | |
}); | |
const thumbPosition = progress.interpolate({ | |
inputRange: [0, 1], | |
outputRange: [0, 16], | |
extrapolate: 'clamp', | |
}); | |
const panResponder = React.useRef( | |
PanResponder.create({ | |
onStartShouldSetPanResponder: () => true, | |
onMoveShouldSetPanResponder: () => true, | |
onPanResponderGrant: (e) => { | |
const seekProgress = e.nativeEvent.locationX / seekbarWidth.current; | |
props.onSeekBarTouch(seekProgress); | |
progress.setValue(seekProgress); | |
}, | |
onPanResponderStart: (e, gestureState) => {}, | |
onPanResponderMove: (e, gestureState) => { | |
const seekProgress = e.nativeEvent.locationX / seekbarWidth.current; | |
props.onSeekBarMove(seekProgress); | |
progress.setValue(seekProgress); | |
}, | |
onPanResponderRelease: (e) => { | |
const seekProgress = e.nativeEvent.locationX / seekbarWidth.current; | |
props.onSeekBarRelease(seekProgress); | |
progress.setValue(seekProgress); | |
}, | |
}), | |
).current; | |
// --------------- EXPOSE METHODS --------------- | |
React.useImperativeHandle(ref, () => ({ | |
setProgress, | |
})); | |
// --------------- EVENTS --------------- | |
React.useEffect(() => { | |
isFullScreen.current = props.isFullScreen; | |
}, [props.isFullScreen]); | |
// --------------- METHODS --------------- | |
/** | |
* Function to animate seekbar progress on video/music progress from 0 to 100% | |
*/ | |
const setProgress = (toProgress = 0, duration = 300) => { | |
Animated.timing(progress, { | |
toValue: toProgress, | |
duration, | |
useNativeDriver: false, | |
easing: Easing.linear, | |
}).start(); | |
}; | |
return ( | |
<Animated.View | |
onLayout={(e) => { | |
seekbarWidth.current = e.nativeEvent.layout.width; | |
}} | |
style={[styles.container, props.style]} | |
> | |
<Animated.View style={styles.wrapper} {...panResponder.panHandlers}> | |
<View | |
style={[styles.track, { backgroundColor: props.trackColor }]} | |
pointerEvents={'none'} | |
> | |
<Animated.View | |
style={[ | |
styles.fill, | |
{ | |
width: progressWidth, | |
}, | |
{ backgroundColor: props.progressColor }, | |
]} | |
pointerEvents={'none'}/> | |
<Animated.View | |
style={[ | |
styles.thumb, | |
{ transform: [{ translateX: thumbPosition }] }, | |
{ backgroundColor: props.thumbColor }, | |
]} | |
pointerEvents={'none'}/> | |
</View> | |
</Animated.View> | |
</Animated.View> | |
); | |
}); | |
SeekBar.defaultProps = { | |
progressColor: 'rgb(252, 70, 119)', | |
trackColor: Colors.OVERLAY_LIGHT_30, | |
thumbColor: 'white', | |
thumbScale: 1, | |
thumbActiveScale: 1.2, | |
removeBaseWidth: 0, | |
}; | |
export default memo(SeekBar); | |
const styles = StyleSheet.create({ | |
container: { | |
height: TRACK_HEIGHT, | |
flex: 1, | |
}, | |
wrapper: { | |
justifyContent: 'center', | |
position: 'absolute', | |
left: 0, | |
right: 0, | |
height: '100%', | |
backgroundColor: Colors.TRANSPARENT, | |
}, | |
track: { | |
height: 4, | |
width: '100%', | |
position: 'relative', | |
flexDirection: 'row', | |
alignItems: 'center', | |
}, | |
fill: { | |
height: 4, | |
}, | |
thumb: { | |
width: 16, | |
height: 16, | |
borderRadius: 50, | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment