yarn add react- native- sound
yarn add @react- native- community/ slider
import Sound from 'react-native-sound'
Sound. setCategory ( 'Playback' ) ;
let sound : Sound;
const initPlayer = ( filepath : string) => {
return new Promise ( ( resolve, reject ) => {
sound = new Sound ( filepath, undefined , error => {
if ( error) {
console. log ( '初始播放器失败' , error) ;
reject ( error) ;
} else {
console. log ( '初始播放器成功' ) ;
resolve ( sound) ;
}
} ) ;
} ) ;
} ;
const playComplete = ( ) => {
return new Promise ( ( resolve, reject ) => {
if ( sound) {
sound. play ( success => {
if ( success) {
console. log ( '播放完了' ) ;
resolve ( sound) ;
} else {
console. log ( '播放失败' ) ;
reject ( ) ;
}
sound. release ( )
} ) ;
} else {
console. log ( '播放失败222' ) ;
reject ( ) ;
}
} ) ;
} ;
const playRelease = ( ) => {
if ( sound) {
console. log ( '释放' ) ;
sound. release ( )
}
}
const playPause = ( ) => {
return new Promise < void > ( ( resolve, reject ) => {
if ( sound) {
sound. pause ( ( ) => {
console. log ( '暂停' ) ;
resolve ( ) ;
} ) ;
} else {
console. log ( '暂停失败' ) ;
reject ( ) ;
}
} ) ;
} ;
const playStop = ( ) => {
return new Promise < void > ( ( resolve, reject ) => {
if ( sound) {
sound. stop ( ( ) => {
console. log ( '停止' ) ;
resolve ( ) ;
} ) ;
} else {
console. log ( '停止失败' ) ;
reject ( ) ;
}
} ) ;
} ;
const getCurrentTime = ( ) => {
return new Promise ( ( resolve, reject ) => {
if ( sound && sound. isLoaded ( ) ) {
sound. getCurrentTime ( seconds => {
resolve ( seconds) ;
} ) ;
} else {
reject ( ) ;
}
} ) ;
} ;
const getDuration = ( ) => {
if ( sound) {
return sound. getDuration ( )
}
return 0
}
const setCurrentTime = ( value : number) => {
if ( sound) {
sound. setCurrentTime ( value)
}
}
export { initPlayer, playComplete, playPause, playStop, playRelease, setCurrentTime, getCurrentTime, getDuration } ;
const getTimeString = ( seconds : number) => {
const m = parseInt ( ( seconds % ( 60 * 60 ) ) / 60 + '' , 10 ) ;
const s = parseInt ( ( seconds % 60 ) + '' , 10 ) ;
return ( m < 10 ? '0' + m : m) + ':' + ( s < 10 ? '0' + s : s) ;
}
import React, { Component } from 'react' ;
import { RouteProp } from '@react-navigation/native' ;
import { RootStackNavigation, RootStackParamList } from '@/navigator/index' ;
import { View, StyleSheet, Image, Text } from 'react-native' ;
import { getAudioDetail } from '@/pages/home/audiodetail/service'
import { AudioDetailType } from '@/pages/home/audiodetail/data'
import { initPlayer, playComplete, playPause, playStop, setCurrentTime, getCurrentTime, getDuration, playRelease } from '@/utils/sound'
import Touchable from '@/components/touchable' ;
import IconFont from '@/assets/iconfont' ;
import { pTd, getTimeString } from '@/utils/index'
import Slider from '@react-native-community/slider' ;
type Iprops = {
route: RouteProp< RootStackParamList, 'AudioDetail' >
navigation: RootStackNavigation,
}
type IState = {
detailDatas: AudioDetailType,
playState: 'playing' | 'paused' | 'finish' | String;
timer: any,
sliderValue: number,
sliderTime: string
}
class AudioDetail extends Component < Iprops, IState> {
state = {
detailDatas: {
id: '' ,
title: '' ,
thumbnailUrl: '' ,
soundUrl: ''
} ,
playState: 'paused' ,
timer: undefined ,
sliderValue: 0 ,
sliderTime: '00:00'
}
componentDidMount ( ) {
this . onCreateFun ( )
this . listenAudio ( )
}
componentWillUnmount ( ) {
const { timer } = this . state
if ( timer) {
clearInterval ( timer)
}
playStop ( ) . then ( res => {
playRelease ( )
} )
}
listenAudio = ( ) => {
let timer = setInterval ( ( ) => {
const { playState } = this . state
if ( playState !== 'playing' ) return
getCurrentTime ( )
. then ( seconds => {
if ( playState !== 'playing' ) return
console. log ( seconds)
this . setState ( {
sliderValue: Number ( seconds) ,
sliderTime: getTimeString ( Number ( seconds) )
} )
} ) . catch ( err => {
} )
} , 1000 ) ;
this . setState ( {
timer
} )
}
onCreateFun = async ( ) => {
const { route : { params : { id } } , navigation } = this . props
const response = await getAudioDetail ( { id } ) . catch ( err => {
console. log ( '出错了' , err)
} )
if ( response && response instanceof Object ) {
const { data, data : { soundUrl } } = response
this . setState ( {
detailDatas: { ... data }
} )
navigation. setOptions ( {
headerTitle: data. title
} )
initPlayer ( soundUrl) . then ( res => {
this . setState ( {
playState: 'playing'
} )
playComplete ( ) . then ( res => {
this . setState ( {
playState: 'finish' ,
sliderValue: 0 ,
sliderTime: '00:00'
} )
} ) . catch ( ( ) => {
this . setState ( {
playState: 'paused'
} )
} )
} ) . catch ( res => {
this . setState ( {
playState: 'paused'
} )
} )
}
}
render ( ) {
const { detailDatas, playState, sliderValue, sliderTime } = this . state
return (
< View style= { styles. container} >
< View style= { styles. imageView} >
{
detailDatas. thumbnailUrl ? (
< Image style= { styles. thumbnailUrl} source= { {
uri: detailDatas?. thumbnailUrl
} } / >
) : null
}
< / View>
< View style= { styles. sliderView} >
< View style= { styles. sliderTimeView} >
< Text style= { styles. sliderTime} > { sliderTime} < / Text>
< / View>
< Slider
style= { styles. slider}
minimumValue= { 0 }
value= { sliderValue}
thumbTintColor= '#FF0000'
maximumValue= { getDuration ( ) }
minimumTrackTintColor= "#FF0000"
maximumTrackTintColor= "#cccccc"
onSlidingComplete= { ( value ) => {
if ( playState === 'playing' ) {
setCurrentTime ( value)
} else if ( playState === 'finish' ) {
initPlayer ( detailDatas. soundUrl) . then ( res => {
this . setState ( {
playState: 'playing'
} )
setCurrentTime ( value)
playComplete ( ) . then ( res => {
this . setState ( {
playState: 'finish' ,
sliderValue: 0 ,
sliderTime: '00:00'
} )
} ) . catch ( ( ) => {
this . setState ( {
playState: 'paused'
} )
} )
} ) . catch ( res => {
this . setState ( {
playState: 'paused'
} )
} )
} else {
this . setState ( {
playState: 'playing'
} )
setCurrentTime ( value)
playComplete ( ) . then ( res => {
this . setState ( {
playState: 'finish' ,
sliderValue: 0 ,
sliderTime: '00:00'
} )
} ) . catch ( ( ) => {
this . setState ( {
playState: 'paused'
} )
} )
}
} }
/ >
< View style= { styles. durationView} >
< Text style= { styles. duration} > { getTimeString ( getDuration ( ) ) } < / Text>
< / View>
< / View>
< View style= { styles. playBtn} >
< Touchable onPress= { ( ) => {
if ( playState === 'playing' ) {
playPause ( ) . then ( res => {
this . setState ( {
playState: 'paused'
} )
} )
} else if ( playState === 'finish' ) {
initPlayer ( detailDatas. soundUrl) . then ( res => {
this . setState ( {
playState: 'playing'
} )
playComplete ( ) . then ( res => {
this . setState ( {
playState: 'finish' ,
sliderValue: 0 ,
sliderTime: '00:00'
} )
} ) . catch ( ( ) => {
this . setState ( {
playState: 'paused'
} )
} )
} ) . catch ( res => {
this . setState ( {
playState: 'paused'
} )
} )
} else {
this . setState ( {
playState: 'playing'
} )
playComplete ( ) . then ( res => {
this . setState ( {
playState: 'finish'
} )
} ) . catch ( ( ) => {
this . setState ( {
playState: 'paused'
} )
} )
}
} } >
< IconFont name= { playState === 'playing' ? 'iconzanting' : 'iconkaishi' } color= { '#f00' } size= { 56 } / >
< / Touchable>
< / View>
< / View>
) ;
}
}
const styles = StyleSheet. create ( {
container: {
} ,
imageView: {
padding: pTd ( 25 ) ,
} ,
thumbnailUrl: {
height: pTd ( 600 ) ,
borderRadius: pTd ( 20 ) ,
backgroundColor: 'red' ,
} ,
sliderView: {
paddingTop: pTd ( 10 ) ,
paddingRight: pTd ( 40 ) ,
paddingLeft: pTd ( 40 ) ,
flexDirection: 'row' ,
alignItems: 'center'
} ,
sliderTimeView: { } ,
sliderTime: {
fontSize: pTd ( 28 ) ,
color: 'red'
} ,
durationView: {
} ,
duration: {
fontSize: pTd ( 28 ) ,
color: '#000000'
} ,
slider: {
flex: 1 ,
height: pTd ( 30 ) ,
borderRadius: pTd ( 10 )
} ,
playBtn: {
marginTop: pTd ( 20 ) ,
alignItems: 'center' ,
} ,
} )
export default AudioDetail;