Skip to content

Commit 21e3cfa

Browse files
Implement with react-native-gesture-handler (#1)
Implement with react-native-gesture-handler
2 parents ce4bffe + 5944df5 commit 21e3cfa

2 files changed

Lines changed: 83 additions & 66 deletions

File tree

index.js

Lines changed: 77 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import React, { Component } from 'react'
2-
import PropTypes from 'prop-types'
32
import {
43
View,
54
StyleSheet,
65
Text,
7-
TouchableWithoutFeedback,
8-
PanResponder,
96
Animated,
107
} from 'react-native'
118

9+
import {
10+
PanGestureHandler,
11+
TapGestureHandler,
12+
State,
13+
} from 'react-native-gesture-handler';
14+
15+
1216
const DefaultColors = {
1317
valueColor: '#999',
1418
trackBackgroundColor: '#DDD',
@@ -64,6 +68,23 @@ export default class extends Component {
6468
startingNumberValue: props.value,
6569
};
6670

71+
72+
this._translateX = new Animated.Value(0);
73+
this._translateY = new Animated.Value(0);
74+
75+
this._lastOffset = { x: 0, y: 0 };
76+
this._onGestureEvent = Animated.event(
77+
[
78+
{
79+
nativeEvent: {
80+
translationX: this._translateX,
81+
translationY: this._translateY,
82+
},
83+
},
84+
],
85+
{ useNativeDriver: false }
86+
);
87+
6788
this.initiateAnimator();
6889

6990
}
@@ -72,7 +93,7 @@ export default class extends Component {
7293
}
7394

7495
componentWillUnmount() {
75-
this.animatedValue.removeAllListeners();
96+
this._translateX.removeAllListeners();
7697
}
7798

7899
scaleUp = () => {
@@ -89,52 +110,46 @@ export default class extends Component {
89110
}).start();
90111
}
91112

92-
createPanHandler = () => PanResponder.create({
93-
onPanResponderTerminationRequest: () => false,
94-
onStartShouldSetPanResponder: ( event, gestureState ) => true,
95-
onMoveShouldSetPanResponder: (event, gestureState) => true,
96-
onPanResponderGrant: ( event, gestureState) => {
113+
_onHandlerStateChange = event => {
114+
115+
if (event.nativeEvent.state === State.BEGAN) {
97116
const { totalDuration, value } = this.props;
98117
const currentPercent = totalDuration !== 0 ? Math.min(totalDuration, value) / totalDuration : 0
99118
const initialX = currentPercent * this.state.dimensionWidth
100119
const boundedX = Math.min(Math.max(initialX, 0), this.state.dimensionWidth - TrackSliderSize);
101120

102-
this.lastDx = 0
103121
this.panResonderMoved = false;
104122

105-
this.animatedValue.setOffset({
106-
x: boundedX,
107-
y: 0
108-
})
109-
this.animatedValue.setValue({
110-
x: 0,
111-
y: 0
112-
})
123+
this._lastOffset.x = boundedX
113124

114125
this.setState({ scrubbing: true }, this.scaleUp);
115-
},
116-
onPanResponderMove: (evt, gestureState) => {
126+
} else if (event.nativeEvent.state === State.ACTIVE) {
117127
this.panResonderMoved = true;
118-
const stepValue = (gestureState.dx - this.lastDx) * this.state.scrubRate;
119-
this.lastDx = gestureState.dx
120-
const newDxValue = this.animatedValue.x._value + (stepValue);
121-
this.animatedValue.setValue({x: newDxValue, y: gestureState.dy})
122-
},
123-
onPanResponderRelease: (evt, gestureState) => {
128+
this._lastOffset.x += event.nativeEvent.translationX;
129+
this._lastOffset.y += event.nativeEvent.translationY;
130+
this._translateX.setOffset(this._lastOffset.x);
131+
this._translateX.setValue(0);
132+
this._translateY.setOffset(this._lastOffset.y);
133+
this._translateY.setValue(0);
134+
} else if (event.nativeEvent.state === State.END) {
124135
const { dimensionWidth } = this.state;
125136
const { totalDuration } = this.props;
126137

127-
const boundedX = Math.min(Math.max(this.value.x, 0), dimensionWidth);
138+
this._lastOffset.x = this._lastOffset.x + this._translateX._value
139+
140+
const boundedX = Math.min(Math.max(this._lastOffset.x, 0), dimensionWidth);
128141

129142
const percentScrubbed = boundedX / dimensionWidth;
130143
const scrubbingValue = percentScrubbed * totalDuration
131144

132145
if(this.panResonderMoved) {
133146
this.onSlidingComplete(scrubbingValue)
134147
}
148+
135149
this.setState({ scrubbing: false, scrubRate: 1 }, this.scaleDown);
150+
136151
}
137-
})
152+
};
138153

139154
formattedStartingNumber = () => {
140155
const { scrubbing, startingNumberValue } = this.state;
@@ -210,23 +225,15 @@ export default class extends Component {
210225
}
211226

212227
initiateAnimator = () => {
213-
214-
this.animatedValue = new Animated.ValueXY({x: 0, y: 0 })
215-
this.value = {x: 0, y: 0 }
216-
this.lastDx = 0
217-
218-
this.animatedValue.addListener((value) => {
219-
const boundedValue = Math.min(Math.max(value.x, 0), this.state.dimensionWidth);
228+
this._translateX.addListener(({ value }) => {
229+
const boundedValue = Math.min(Math.max(value, 0), this.state.dimensionWidth);
220230

221-
this.handleScrubRateChange(value);
222-
223231
this.setState({
224232
startingNumberValue: (boundedValue / this.state.dimensionWidth) * this.props.totalDuration,
225233
endingNumberValue: (1 - (boundedValue / this.state.dimensionWidth)) * this.props.totalDuration
226234
})
227-
return this.value = value
235+
return;
228236
});
229-
this.panResponder = this.createPanHandler()
230237
}
231238

232239
render() {
@@ -253,7 +260,6 @@ export default class extends Component {
253260
const progressPercent = totalDuration !== 0 ? cappedValue / totalDuration : 0;
254261
const displayPercent = progressPercent * (dimensionWidth);
255262
const progressWidth = progressPercent * 100
256-
257263
const bufferedProgressPercent = totalDuration !== 0 ? cappedBufferedValue / totalDuration : 0;
258264
const bufferedProgressWidth = bufferedProgressPercent * 100
259265

@@ -278,7 +284,7 @@ export default class extends Component {
278284
let boundX = progressPercent
279285

280286
if(dimensionWidth) {
281-
boundX = this.animatedValue.x.interpolate({
287+
boundX = this._translateX.interpolate({
282288
inputRange: [0, dimensionWidth],
283289
outputRange: [0, dimensionWidth],
284290
extrapolate: 'clamp'
@@ -309,32 +315,35 @@ export default class extends Component {
309315
style={[
310316
styles.progressTrack,
311317
{ ...progressTrackStyle },
312-
!scrubbing
318+
!scrubbing
313319
? { width: `${progressWidth}%`}
314320
: { width: boundX }
315-
316321
]}
317322
/>
318-
319-
<Animated.View
320-
key='progressTrack'
321-
style={[
322-
styles.trackSlider,
323-
{ ...scrubberColor },
324-
// { left: progressPercent * dimensionWidth },
325-
326-
!scrubbing
327-
? { transform: [{translateX: displayPercent}, scaleStyle] }
328-
: { transform: [{translateX: boundX}, scaleStyle] },
329-
330-
!scrubbing
331-
? { transform: [{translateX: displayPercent}, scaleStyle] }
332-
: { transform: [{translateX: boundX}, scaleStyle] },
333-
334-
]}
335-
{...this.panResponder.panHandlers}
336-
hitSlop={{top: 50, bottom: 50, left: 50, right: 50}}
337-
/>
323+
<PanGestureHandler
324+
onGestureEvent={this._onGestureEvent}
325+
onHandlerStateChange={this._onHandlerStateChange}
326+
minDist={0}
327+
>
328+
<Animated.View
329+
style={[
330+
styles.trackSliderWrapper,
331+
!scrubbing
332+
? { left: displayPercent - (TrackSliderSize / 2) }
333+
: { transform: [{translateX: boundX}] },
334+
]}
335+
hitSlop={{top: 20, bottom: 20, left: 50, right: 50}}
336+
>
337+
<Animated.View
338+
key='progressTrack'
339+
style={[
340+
styles.trackSlider,
341+
{ ...scrubberColor },
342+
{ transform: [scaleStyle] },
343+
]}
344+
/>
345+
</Animated.View>
346+
</PanGestureHandler>
338347
</View>
339348

340349
<View style={styles.valuesContainer} >
@@ -387,12 +396,15 @@ const styles = StyleSheet.create({
387396
borderBottomLeftRadius: 3,
388397
zIndex: 1,
389398
},
399+
trackSliderWrapper: {
400+
zIndex: 3,
401+
position: 'absolute',
402+
left: 0 - (TrackSliderSize / 2),
403+
},
390404
trackSlider: {
391405
width: TrackSliderSize,
392406
height: TrackSliderSize,
393407
borderRadius: TrackSliderSize,
394408
borderColor: '#fff',
395-
zIndex: 3,
396-
position: 'absolute',
397409
}
398410
});

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-scrubber",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "A Scrubber component for handling audio/video within React Native",
55
"main": "index.js",
66
"scripts": {
@@ -21,6 +21,11 @@
2121
"swipper",
2222
"controls"
2323
],
24+
"peerDependencies": {
25+
"react": "*",
26+
"react-native": "*",
27+
"react-native-gesture-handler": "*"
28+
},
2429
"author": "Repod",
2530
"license": "ISC",
2631
"bugs": {

0 commit comments

Comments
 (0)