diff --git a/CHANGELOG.md b/CHANGELOG.md
index 28957be..05cefe4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.6.0
+ - The seekBar is now seek-able.
+ - Added `seekBarKnob` to `customStyles` to style the seek bar knob.
+
## 0.2.0
- `resizeMode` prop added, now defaults to `contain`
diff --git a/README.md b/README.md
index 5d8a35a..48497d0 100644
--- a/README.md
+++ b/README.md
@@ -46,14 +46,16 @@ All other props are passed to the react-native-video component.
- playIcon
- seekBar
- seekBarProgress
+ - seekBarKnob
- thumbnail
- playButton
- playArrow
## Future features
-- [ ] Make seek bar seekable.
+- [X] Make seek bar seekable.
- [x] Make player customizable.
- [ ] Add volume control
-- [ ] Add fullscreen button
+- [X] Add fullscreen button
+ - [ ] Add fullscreen button for android
- [ ] Add loader
diff --git a/index.js b/index.js
index 1d97d96..ff150e4 100644
--- a/index.js
+++ b/index.js
@@ -52,6 +52,15 @@ const styles = StyleSheet.create({
seekBarProgress: {
backgroundColor: '#F00',
},
+ seekBarKnob: {
+ width: 20,
+ height: 20,
+ borderRadius: 10,
+ marginHorizontal: -10,
+ marginVertical: -8.5,
+ backgroundColor: '#F00',
+ transform: [{ scale: 0.8 }],
+ },
overlayButton: {
flex: 1,
},
@@ -69,8 +78,14 @@ export default class VideoPlayer extends Component {
isMuted: props.defaultMuted,
isControlsVisible: !props.hideControlsOnStart,
duration: 0,
+ isSeeking: false,
};
+ this.seekBarWidth = 200;
+ this.wasPlayingBeforeSeek = props.autoplay;
+ this.seekTouchStart = 0;
+ this.seekProgressStart = 0;
+
this.onLayout = this.onLayout.bind(this);
this.onStartPress = this.onStartPress.bind(this);
this.onProgress = this.onProgress.bind(this);
@@ -80,6 +95,10 @@ export default class VideoPlayer extends Component {
this.onMutePress = this.onMutePress.bind(this);
this.showControls = this.showControls.bind(this);
this.onToggleFullScreen = this.onToggleFullScreen.bind(this);
+ this.onSeekBarLayout = this.onSeekBarLayout.bind(this);
+ this.onSeekGrant = this.onSeekGrant.bind(this);
+ this.onSeekRelease = this.onSeekRelease.bind(this);
+ this.onSeek = this.onSeek.bind(this);
}
componentDidMount() {
@@ -105,6 +124,9 @@ export default class VideoPlayer extends Component {
}
onProgress(event) {
+ if (this.state.isSeeking) {
+ return;
+ }
if (this.props.onProgress) {
this.props.onProgress(event);
}
@@ -157,6 +179,49 @@ export default class VideoPlayer extends Component {
this.player.presentFullscreenPlayer();
}
+ onSeekBarLayout({ nativeEvent }) {
+ this.seekBarWidth = nativeEvent.layout.width;
+ }
+
+ onSeekStartResponder() {
+ return true;
+ }
+
+ onSeekMoveResponder() {
+ return true;
+ }
+
+ onSeekGrant(e) {
+ this.seekTouchStart = e.nativeEvent.pageX;
+ this.seekProgressStart = this.state.progress;
+ this.wasPlayingBeforeSeek = this.state.isPlaying;
+ this.setState({
+ isSeeking: true,
+ isPlaying: false,
+ });
+ }
+
+ onSeekRelease() {
+ this.setState({
+ isSeeking: false,
+ isPlaying: this.wasPlayingBeforeSeek,
+ });
+ this.showControls();
+ }
+
+ onSeek(e) {
+ const diff = e.nativeEvent.pageX - this.seekTouchStart;
+ const ratio = 100 / this.seekBarWidth;
+ const progress = this.seekProgressStart + ((ratio * diff) / 100);
+
+
+ this.setState({
+ progress,
+ });
+
+ this.player.seek(progress * this.state.duration);
+ }
+
getSizeStyles() {
const { videoWidth, videoHeight } = this.props;
const { width } = this.state;
@@ -225,6 +290,7 @@ export default class VideoPlayer extends Component {
},
customStyles.seekBar,
]}
+ onLayout={this.onSeekBarLayout}
>
+ { !fullWidth ? (
+
+ ) : null }
);
@@ -366,6 +448,8 @@ VideoPlayer.propTypes = {
playIcon: Icon.propTypes.style,
seekBar: View.propTypes.style,
seekBarProgress: View.propTypes.style,
+ seekBarKnob: View.propTypes.style,
+ seekBarKnobSeeking: View.propTypes.style,
thumbnail: Image.propTypes.style,
playButton: TouchableOpacity.propTypes.style,
playArrow: Icon.propTypes.style,