使用 react-native-track-player 从 flatlist 播放选定的歌曲

Posted

技术标签:

【中文标题】使用 react-native-track-player 从 flatlist 播放选定的歌曲【英文标题】:Using react-native-track-player to play selected song from flatlist 【发布时间】:2021-04-07 14:23:54 【问题描述】:

我不知道如何从平面列表中播放选定的曲目/歌曲,我已经有一个 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>
  );

【问题讨论】:

【参考方案1】:
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和本地文件路径,请确保在运行前适当修改本地文件路径

【讨论】:

以上是关于使用 react-native-track-player 从 flatlist 播放选定的歌曲的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)