使用 react-native-track-player 从 flatlist 播放选定的歌曲
Using react-native-track-player to play selected song from flatlist
我不知道如何播放从 flatlist 中选择的 track/song,我已经有一个 playerscreen.js 可以播放我的歌曲列表中的歌曲。我想实现用户搜索歌曲并从平面列表中选择列表中播放歌曲。下面是我的 songlist.js
const Songlist = () => {
const [loading, setLoading] = useState(false);
const navigation = useNavigation();
renderFooter = () => {
if (!loading) return null
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: '#CED0CE',
}}
>
<ActivityIndicator animating size='large' />
</View>
)
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '86%',
backgroundColor: '#CED0CE',
marginLeft: '5%',
}}
/>
)
}
return (
<View>
<FlatList
data={songs}
keyExtractor={item => item.id}
renderItem={({ item, index }) => (
<TouchableOpacity
onPress={() => navigation.navigate('Player')}
>
<View
style={{
flexDirection: 'row',
padding: 16,
alignItems: 'center',
}}
>
<Avatar
source={{ uri: item.artwork.thumbnail }}
size='giant'
style={{ marginRight: 16 }}
/>
<Text
category='s1'
style={{color: '#000'}}
>{`${item.title}`}</Text>
</View>
<Text
category='s2'
style={{color: '#999', marginHorizontal: 80, bottom: 20}}
>Genre: {`${item.genre}`}</Text>
</TouchableOpacity>
)}
ItemSeparatorComponent={renderSeparator}
ListFooterComponent={renderFooter}
/>
</View>
);
}
export default Songlist;
这是我的初始playerscreen.js
export default function PlayerScreen() {
const navigation = useNavigation();
const scrollX = useRef(new Animated.Value(0)).current;
const slider = useRef(null);
const isPlayerReady = useRef(false);
const index = useRef(0);
const [songIndex, setSongIndex] = useState(0);
const isItFromUser = useRef(true);
// for tranlating the album art
const position = useRef(Animated.divide(scrollX, width)).current;
const playbackState = usePlaybackState();
useEffect(() => {
// position.addListener(({ value }) => {
// console.log(value);
// });
scrollX.addListener(({value}) => {
const val = Math.round(value / width);
setSongIndex(val);
});
TrackPlayer.setupPlayer().then(async () => {
// The player is ready to be used
console.log('Player ready');
// add the array of songs in the playlist
await TrackPlayer.reset();
await TrackPlayer.add(songs);
TrackPlayer.play();
isPlayerReady.current = true;
await TrackPlayer.updateOptions({
stopWithApp: false,
alwaysPauseOnInterruption: true,
capabilities: [
Capability.Play,
Capability.Pause,
Capability.SkipToNext,
Capability.SkipToPrevious,
],
});
//add listener on track change
TrackPlayer.addEventListener(Event.PlaybackTrackChanged, async (e) => {
console.log('song ended', e);
const trackId = (await TrackPlayer.getCurrentTrack()) - 1; //get the current id
console.log('track id', trackId, 'index', index.current);
if (trackId !== index.current) {
setSongIndex(trackId);
isItFromUser.current = false;
if (trackId > index.current) {
goNext();
} else {
goPrv();
}
setTimeout(() => {
isItFromUser.current = true;
}, 200);
}
// isPlayerReady.current = true;
});
//monitor intterupt when other apps start playing music
TrackPlayer.addEventListener(Event.RemoteDuck, (e) => {
// console.log(e);
if (e.paused) {
// if pause true we need to pause the music
TrackPlayer.pause();
} else {
TrackPlayer.play();
}
});
});
return () => {
scrollX.removeAllListeners();
TrackPlayer.destroy();
// exitPlayer();
};
}, []);
// change the song when index changes
useEffect(() => {
if (isPlayerReady.current && isItFromUser.current) {
TrackPlayer.skip(songs[songIndex].id)
.then((_) => {
console.log('changed track');
})
.catch((e) => console.log('error in changing track ', e));
}
index.current = songIndex;
}, [songIndex]);
const exitPlayer = async () => {
try {
await TrackPlayer.stop();
} catch (error) {
console.error('exitPlayer', error);
}
};
const goNext = async () => {
slider.current.scrollToOffset({
offset: (index.current + 1) * width,
});
await TrackPlayer.play();
};
const goPrv = async () => {
slider.current.scrollToOffset({
offset: (index.current - 1) * width,
});
await TrackPlayer.play();
};
const renderItem = ({index, item}) => {
return (
<Animated.View
style={{
alignItems: 'center',
width: width,
transform: [
{
translateX: Animated.multiply(
Animated.add(position, -index),
-100,
),
},
],
}}>
<Animated.Image
source={item.artwork}
style={{width: 320, height: 320, borderRadius: 5}}
/>
</Animated.View>
);
};
return (
<SafeAreaView style={styles.container}>
<SafeAreaView style={{height: 320}}>
<Animated.FlatList
ref={slider}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
scrollEventThrottle={16}
data={songs}
renderItem={renderItem}
keyExtractor={(item) => item.id}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: scrollX}}}],
{useNativeDriver: true},
)}
/>
</SafeAreaView>
<TouchableOpacity
style={styles.genreContainer}
onPress={() => navigation.navigate('Genre')}
>
<SimpleLineIcons name="playlist" size={20} color='#fff' />
<Text style={styles.genre}> Genre</Text>
</TouchableOpacity>
<View>
<Text style={styles.title}>{songs[songIndex].title}</Text>
<Text style={styles.artist}>{songs[songIndex].artist}</Text>
</View>
<SliderComp />
<Controller onNext={goNext} onPrv={goPrv} />
</SafeAreaView>
);
}
import React from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar, ScrollView, TouchableOpacity } from 'react-native';
import Sound from 'react-native-sound';
const MusicApp = () => {
const DATA = [
{
title: 'Advertising Local',
isRequire: true,
url: require('./resource/advertising.mp3'),
},
{
title: 'Advertising URL',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/advertising.mp3',
},
{
title: 'Hosana',
isRequire: true,
url: require('./Hosana.mp3'),
},
{
title: 'Play aac sound from remote URL',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/pew2.aac',
},
{
title: 'Frog wav sound from Local',
isRequire: true,
url: require('./resource/frog.wav'),
},
{
title: 'Frog wav sound from remote URL',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/frog.wav',
},
];
let sound;
const playSound =(item, id)=>{
console.log("the url is "+ item.url);
if(item.url !=1){
sound = new Sound(item.url, '', (error, _sound) => {
if (error) {
alert('error' + error.message);
return;
}
stopSound
sound.play(() => {
sound.release();
});
});
}else{
sound = new Sound(item.url, (error, _sound) => {
if (error) {
alert('error' + error.message);
return;
}
stopSound
sound.play(() => {
sound.release();
});
});
}
}
const stopSound =(index)=>{
sound.stop(() => {
console.log('Stop');
});
}
const renderItem = ({ item, index }) => (
<ScrollView style={{flex: 1}}>
<View style={styles.item}>
<Text style={styles.title}> {item.title} </Text>
<TouchableOpacity onPress={()=>playSound(item, index)} style={{padding: 10, backgroundColor: 'blue'}}><Text>Play</Text></TouchableOpacity>
<TouchableOpacity onPress={()=>stopSound(index)} style={{padding: 10, backgroundColor: 'red'}}><Text>Stop</Text></TouchableOpacity>
</View>
</ScrollView>
);
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 20,
},
});
export default MusicApp;
注意:
做 yarn add react-native-sound 或 npm install react-native-sound。
其次,音乐有两个来源-远程url和本地文件路径,请确保在运行
之前适当修改本地文件路径
我不知道如何播放从 flatlist 中选择的 track/song,我已经有一个 playerscreen.js 可以播放我的歌曲列表中的歌曲。我想实现用户搜索歌曲并从平面列表中选择列表中播放歌曲。下面是我的 songlist.js
const Songlist = () => {
const [loading, setLoading] = useState(false);
const navigation = useNavigation();
renderFooter = () => {
if (!loading) return null
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: '#CED0CE',
}}
>
<ActivityIndicator animating size='large' />
</View>
)
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '86%',
backgroundColor: '#CED0CE',
marginLeft: '5%',
}}
/>
)
}
return (
<View>
<FlatList
data={songs}
keyExtractor={item => item.id}
renderItem={({ item, index }) => (
<TouchableOpacity
onPress={() => navigation.navigate('Player')}
>
<View
style={{
flexDirection: 'row',
padding: 16,
alignItems: 'center',
}}
>
<Avatar
source={{ uri: item.artwork.thumbnail }}
size='giant'
style={{ marginRight: 16 }}
/>
<Text
category='s1'
style={{color: '#000'}}
>{`${item.title}`}</Text>
</View>
<Text
category='s2'
style={{color: '#999', marginHorizontal: 80, bottom: 20}}
>Genre: {`${item.genre}`}</Text>
</TouchableOpacity>
)}
ItemSeparatorComponent={renderSeparator}
ListFooterComponent={renderFooter}
/>
</View>
);
}
export default Songlist;
这是我的初始playerscreen.js
export default function PlayerScreen() {
const navigation = useNavigation();
const scrollX = useRef(new Animated.Value(0)).current;
const slider = useRef(null);
const isPlayerReady = useRef(false);
const index = useRef(0);
const [songIndex, setSongIndex] = useState(0);
const isItFromUser = useRef(true);
// for tranlating the album art
const position = useRef(Animated.divide(scrollX, width)).current;
const playbackState = usePlaybackState();
useEffect(() => {
// position.addListener(({ value }) => {
// console.log(value);
// });
scrollX.addListener(({value}) => {
const val = Math.round(value / width);
setSongIndex(val);
});
TrackPlayer.setupPlayer().then(async () => {
// The player is ready to be used
console.log('Player ready');
// add the array of songs in the playlist
await TrackPlayer.reset();
await TrackPlayer.add(songs);
TrackPlayer.play();
isPlayerReady.current = true;
await TrackPlayer.updateOptions({
stopWithApp: false,
alwaysPauseOnInterruption: true,
capabilities: [
Capability.Play,
Capability.Pause,
Capability.SkipToNext,
Capability.SkipToPrevious,
],
});
//add listener on track change
TrackPlayer.addEventListener(Event.PlaybackTrackChanged, async (e) => {
console.log('song ended', e);
const trackId = (await TrackPlayer.getCurrentTrack()) - 1; //get the current id
console.log('track id', trackId, 'index', index.current);
if (trackId !== index.current) {
setSongIndex(trackId);
isItFromUser.current = false;
if (trackId > index.current) {
goNext();
} else {
goPrv();
}
setTimeout(() => {
isItFromUser.current = true;
}, 200);
}
// isPlayerReady.current = true;
});
//monitor intterupt when other apps start playing music
TrackPlayer.addEventListener(Event.RemoteDuck, (e) => {
// console.log(e);
if (e.paused) {
// if pause true we need to pause the music
TrackPlayer.pause();
} else {
TrackPlayer.play();
}
});
});
return () => {
scrollX.removeAllListeners();
TrackPlayer.destroy();
// exitPlayer();
};
}, []);
// change the song when index changes
useEffect(() => {
if (isPlayerReady.current && isItFromUser.current) {
TrackPlayer.skip(songs[songIndex].id)
.then((_) => {
console.log('changed track');
})
.catch((e) => console.log('error in changing track ', e));
}
index.current = songIndex;
}, [songIndex]);
const exitPlayer = async () => {
try {
await TrackPlayer.stop();
} catch (error) {
console.error('exitPlayer', error);
}
};
const goNext = async () => {
slider.current.scrollToOffset({
offset: (index.current + 1) * width,
});
await TrackPlayer.play();
};
const goPrv = async () => {
slider.current.scrollToOffset({
offset: (index.current - 1) * width,
});
await TrackPlayer.play();
};
const renderItem = ({index, item}) => {
return (
<Animated.View
style={{
alignItems: 'center',
width: width,
transform: [
{
translateX: Animated.multiply(
Animated.add(position, -index),
-100,
),
},
],
}}>
<Animated.Image
source={item.artwork}
style={{width: 320, height: 320, borderRadius: 5}}
/>
</Animated.View>
);
};
return (
<SafeAreaView style={styles.container}>
<SafeAreaView style={{height: 320}}>
<Animated.FlatList
ref={slider}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
scrollEventThrottle={16}
data={songs}
renderItem={renderItem}
keyExtractor={(item) => item.id}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: scrollX}}}],
{useNativeDriver: true},
)}
/>
</SafeAreaView>
<TouchableOpacity
style={styles.genreContainer}
onPress={() => navigation.navigate('Genre')}
>
<SimpleLineIcons name="playlist" size={20} color='#fff' />
<Text style={styles.genre}> Genre</Text>
</TouchableOpacity>
<View>
<Text style={styles.title}>{songs[songIndex].title}</Text>
<Text style={styles.artist}>{songs[songIndex].artist}</Text>
</View>
<SliderComp />
<Controller onNext={goNext} onPrv={goPrv} />
</SafeAreaView>
);
}
import React from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar, ScrollView, TouchableOpacity } from 'react-native';
import Sound from 'react-native-sound';
const MusicApp = () => {
const DATA = [
{
title: 'Advertising Local',
isRequire: true,
url: require('./resource/advertising.mp3'),
},
{
title: 'Advertising URL',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/advertising.mp3',
},
{
title: 'Hosana',
isRequire: true,
url: require('./Hosana.mp3'),
},
{
title: 'Play aac sound from remote URL',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/pew2.aac',
},
{
title: 'Frog wav sound from Local',
isRequire: true,
url: require('./resource/frog.wav'),
},
{
title: 'Frog wav sound from remote URL',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/frog.wav',
},
];
let sound;
const playSound =(item, id)=>{
console.log("the url is "+ item.url);
if(item.url !=1){
sound = new Sound(item.url, '', (error, _sound) => {
if (error) {
alert('error' + error.message);
return;
}
stopSound
sound.play(() => {
sound.release();
});
});
}else{
sound = new Sound(item.url, (error, _sound) => {
if (error) {
alert('error' + error.message);
return;
}
stopSound
sound.play(() => {
sound.release();
});
});
}
}
const stopSound =(index)=>{
sound.stop(() => {
console.log('Stop');
});
}
const renderItem = ({ item, index }) => (
<ScrollView style={{flex: 1}}>
<View style={styles.item}>
<Text style={styles.title}> {item.title} </Text>
<TouchableOpacity onPress={()=>playSound(item, index)} style={{padding: 10, backgroundColor: 'blue'}}><Text>Play</Text></TouchableOpacity>
<TouchableOpacity onPress={()=>stopSound(index)} style={{padding: 10, backgroundColor: 'red'}}><Text>Stop</Text></TouchableOpacity>
</View>
</ScrollView>
);
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 20,
},
});
export default MusicApp;
注意: 做 yarn add react-native-sound 或 npm install react-native-sound。 其次,音乐有两个来源-远程url和本地文件路径,请确保在运行
之前适当修改本地文件路径