I am attempting to use react-native-slider with Expo AV to create a seekbar, but am having trouble updating the 'value' state of slider. When I try to set it to currentPosition/durationPosition, it errors out, likely because initially these values are NaN. I CAN display current/duration however.
My best guess is that I need a way to wait until my mp3 is loaded before rendering the SeekBar. I probably also need to do a better job of separating components and keep PlayerScreen very minimal. I've messed around with this code so much I can barely remember what I've tried... Getting close to ditching Expo because react-native-track-player looks easier to work with and I've heard some bad things about Expo. Anyways, here's where I'm at now
export default class PlayerScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
isPlaying: false,
playbackObject: null,
volume: 1.0,
isBuffering: false,
paused: true,
currentIndex: 0,
durationMillis: 1,
positionMillis:0,
sliderValue:0,
isSeeking:false,
}
}
async componentDidMount() {
try {
await Audio.setAudioModeAsync({
allowsRecordingIOS: false,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DUCK_OTHERS,
shouldDuckAndroid: true,
staysActiveInBackground: true,
playThroughEarpieceAndroid: true
})
this.loadAudio()
} catch (e) {
console.log(e)
}
}
async loadAudio() {
const { currentIndex, isPlaying, volume} = this.state
try {
const playbackObject = new Audio.Sound()
const source = {
uri: this.props.route.params.item.uri
}
const status = {
shouldPlay: isPlaying,
volume,
}
playbackObject.setOnPlaybackStatusUpdate(this.onPlaybackStatusUpdate)
await playbackObject.loadAsync(source, status, true)
this.setState({playbackObject})
var sliderValue = this.state.positionMillis/this.state.durationMillis
} catch (e) {
console.log(e)
}
}
handlePlayPause = async () => {
const { isPlaying, playbackObject } = this.state
isPlaying ? await playbackObject.pauseAsync() : await playbackObject.playAsync()
this.setState({
isPlaying: !isPlaying
})
}
onPlaybackStatusUpdate = status => {
this.setState({
isBuffering: status.isBuffering,
durationMillis: status.durationMillis,
positionMillis: status.positionMillis,
})
}
render() {
const { item } = this.props.route.params;
return (
<View style={globalStyles.container}>
<Header />
<View style={globalStyles.subHeader}>
<Text style={globalStyles.title}>{ item.title }</Text>
</View>
<View style={styles.text}>
<Text>{ item.text }</Text>
</View>
<SeekBar
durationMillis={this.state.durationMillis}
positionMillis={this.state.positionMillis}
sliderValue={this.state.sliderValue}
/>
And here's the SeekBar component:
const SeekBar = ({
positionMillis,
durationMillis,
sliderValue
}) => {
return (
<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
<View style={{ flex: 1 }} />
<Text style={[styles.text, { width: 40 }]}>
{positionMillis + ' / ' + durationMillis}
</Text>
</View>
<Slider
minimumValue={0}
maximumValue={1}
value={sliderValue}
style={styles.slider}
minimumTrackTintColor='#fff'
maximumTrackTintColor='rgba(255, 255, 255, 0.14)'
/>
</View>
);
};
export default SeekBar;