1

Here is a Music player app, and it has an UIView(animation Histogram) on each top of tableView's cell(to show the current playing song). Please refer to below screenshot.

enter image description here

/ / / In the 3rd row, that is the animation Histogram on top of song's artwork to indicate current playing song. And what I want to do is to let this animation Histogram move to next song when the song is finish playing.

Currently, I'm using audioPlayerDidFinishPlaying() to trigger the play info changes when song is finish playing. And inside tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) to set the animation image state on the cell.

/ / / My code as below:

  • VC2 (playing scene)
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {

        // Code to change the playing info & track
        if SongData.repeatSequence == "repeatOne" {
            AudioManager.sharedInstance.playTrack(idx: SongData.currentTrack, songList: SongData.songList)

            songTitle.text = SongData.songList[SongData.currentTrack].songName
            songAlbum.text = SongData.songList[SongData.currentTrack].artistName + " - " + SongData.songList[SongData.currentTrack].albumName
            songArtwork.image = SongData.songList[SongData.currentTrack].albumArtwork

        } else if SongData.repeatSequence == "repeatList" {
            // print("play current song done!")

            SongData.currentTrack = (SongData.currentTrack + 1) % (SongData.songList.count)
            AudioManager.sharedInstance.playTrack(idx: SongData.currentTrack, songList: SongData.songList)

            songTitle.text = SongData.songList[SongData.currentTrack].songName
            songAlbum.text = SongData.songList[SongData.currentTrack].artistName + " - " + SongData.songList[SongData.currentTrack].albumName
            songArtwork.image = SongData.songList[SongData.currentTrack].albumArtwork
        } else if SongData.repeatSequence == "shuffle" {
            SongData.currentTrack = Int.random(in: 0 ..< SongData.shuffleSongList.count)
            // SongData.currentTrack = (SongData.currentTrack + 1) % (SongData.songList.count)

            // print("SongData.songList.count", SongData.songList.count)
            AudioManager.sharedInstance.playTrack(idx: SongData.currentTrack, songList: SongData.shuffleSongList)

            songTitle.text = SongData.shuffleSongList[SongData.currentTrack].songName
            songAlbum.text = SongData.shuffleSongList[SongData.currentTrack].artistName + " - " + SongData.shuffleSongList[SongData.currentTrack].albumName
            songArtwork.image = SongData.shuffleSongList[SongData.currentTrack].albumArtwork
            // get index (songList) where the same song in songList from song on shuffleSongList
            NowPlayingViewController.indexFromShuffleList = SongData.songList.firstIndex(where: {$0.songName == songTitle.text}) ?? 0
            // print("=========Shuffle Track=========", NowPlayingViewController.indexFromShuffleList)

            if NowPlayingViewController.indexFromShuffleList >= 0 {
                SongData.currentTrack = NowPlayingViewController.indexFromShuffleList
                NowPlayingViewController.indexFromShuffleList = -1
            }
        }

        // check if song playing is finished
        AudioManager.sharedInstance.audioPlayer.delegate = self
        // SongsTableViewController().tableView.reloadData()
        print("Audio did finish playing")

        updateLockedScreenPlayingInfo()
    }
  • VC1 (SongsTableViewController) same scene as above screenshot, I'm setting the animation image like this cell.config(forState: SongData.isPlaying ? .playing : .paused)
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell

        if resultSearchController.isActive {
            cell.addButton.tag = indexPath.row
            cell.songTitle.text = filteredTableData[indexPath.row].songName
            cell.songArtist.text = filteredTableData[indexPath.row].artistName
            cell.songArtwork.image = filteredTableData[indexPath.row].albumArtwork

            // set dynamic view on albumArtwork
            if SongData.songList.count == 0 {
                cell.config(forState: .nonState)
            } else {
                if filteredTableData[indexPath.row].songName == SongData.songList[SongData.currentTrack].songName {
                    cell.config(forState: SongData.isPlaying ? .playing : .paused)
                } else {
                    cell.config(forState: .nonState)
                }
            }
        } else {
            cell.addButton.tag = indexPath.row
            cell.songTitle.text = tableData[indexPath.row].songName
            cell.songArtist.text = tableData[indexPath.row].artistName
            cell.songArtwork.image = tableData[indexPath.row].albumArtwork
            // return cell

            // set dynamic view on albumArtwork
            if SongData.songList.count == 0 {
                cell.config(forState: .nonState)
            } else {
                if tableData[indexPath.row].songName == SongData.songList[SongData.currentTrack].songName {
                    print("tableData, songName", tableData[indexPath.row].songName)
                    cell.config(forState: SongData.isPlaying ? .playing : .paused)
                } else {
                    // print("no name matches")
                    cell.config(forState: .nonState)
                }
            }
        }
        return cell
    }

/ / / The problem is that after current song's playing is complete, the animation image doesn't move to next one, but if change to other VC and back, the animation image was changed to correct one. Per my investigation, it is because we need to reload the VC2's tableView data in audioPlayerDidFinishPlaying, then I put SongsTableViewController().tableView.reloadData() in the end of audioPlayerDidFinishPlaying. But it is not working, need help here on how to reload the data VC2 from VC1 or if there is other solution to do that?

Zhou Haibo
  • 1,681
  • 1
  • 12
  • 32
  • updateLockedScreenPlayingInfo() what is this function doing ? – Jawad Ali Jan 13 '20 at 17:19
  • where you are setting other audio to play ? – Jawad Ali Jan 13 '20 at 17:20
  • Can you post what your code is in `updateLockedScreenPlayingInfo()`? – Caroline Harrison Jan 13 '20 at 18:08
  • @jawadAli, it is using for change command center displayed info like song name, album artwork...when the screen is locked. And that is not related with this issue. – Zhou Haibo Jan 14 '20 at 03:29
  • @jawadAli, I update VC2 to include the audio change part. Please feel free to have a look. – Zhou Haibo Jan 14 '20 at 03:34
  • @Caroline Harrison, ```updateLockedScreenPlayingInfo()``` is using for locked screen command center, and this part is not fully worked on my app (iOS13) now, it has some small issues I need to work out later and also not related my post question. So I didn't post it, in case mislead other guys. – Zhou Haibo Jan 14 '20 at 03:41
  • Do you have delegate methods in these two classes ? – Jawad Ali Jan 14 '20 at 03:45
  • @jawadAli, yes, VC1 is UITableViewController, which implement those tableView delegate methods, and connect delegate in storyboard. And VC2 is a UIViewController and adopt AVAudioPlayerDelegate protocol. – Zhou Haibo Jan 14 '20 at 04:19

1 Answers1

0

Well, I found the solution on this thread How to reload tableview from another view controller in swift

It is clean and easy to use:

In your tableView Controller:

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(loadList), name: NSNotification.Name(rawValue: "load"), object: nil)
}

func loadList(notification: NSNotification){
    //load data here
    self.tableView.reloadData()
}

Then in the other ViewController :

NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)
Zhou Haibo
  • 1,681
  • 1
  • 12
  • 32