使用 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和本地文件路径,请确保在运行

之前适当修改本地文件路径