Zhou Haibo
Zhou Haibo

Reputation: 2078

How to set specific row cell's image of tableView to dynamic image

As below gif showed, in the specific row of tableView, the playing song's image(Just Dance.mp3) is changed to dynamic image.

My main question is how to achieve this effect in my App, to use a GIF image or other approach? Need advice here.

What effect I want to achieve:

  1. when a song is playing, the specific row cell's image is changed to dynamic image. (the main question)
  2. if the song is paused, then that dynamic image stop to play.
  3. when another song is selected to play, the previous song's(cell) image is resume to its album artwork.

Here is my snip code, I'm not test it yet since I'm not sure if I should use GIF or other approach.

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
            return cell
        } 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 image of specific tableView row cell to GIF image
        if indexPath.row == SongData.currentTrack {
            let image = UIImage(named: "playing-gif-image")
            cell.songArtwork.image = image
        } else {
            // do nothing
        }
    }

enter image description here

===================================================================

Update my code according to ATV's answer, currently I use static image to set different state of playing cell. Well I get interested to this fancy CAShapeLayer:), and I need time to learn about it then to set the dynamic image for the specific cell.

/ / / Model, SongData.swift

import UIKit

class SongData: NSObject, NSCoding {

    var songName: String
    var artistName: String
    var albumName: String
    var albumArtwork: UIImage
    var url: URL

    static var songList = [SongData]()
    static var shuffleSongList = [SongData]()
    static var currentTrack = 0
    static var showCurrentPlayingSong = false
    static var repeatSequence = "repeatList"
    static var isPlaying = false

    enum PlayingCellState {
        case nonState
        case playing
        case paused
    }

    init(songName: String, artistName: String, albumName: String, albumArtwork: UIImage, url: URL) {
        self.songName = songName
        self.artistName = artistName
        self.albumName = albumName
        self.albumArtwork = albumArtwork
        self.url = url
    } 
...
}

/ / / CustomCell.swift

import UIKit

class CustomCell: UITableViewCell {

    @IBOutlet weak var songTitle: UILabel!
    @IBOutlet weak var songArtist: UILabel!
    @IBOutlet weak var songArtwork: UIImageView!
    @IBOutlet weak var addButton: UIButton!

    override func awakeFromNib() {
        super.awakeFromNib()
        songArtwork.layer.cornerRadius = 8.0
    }

    func config(forState state: SongData.PlayingCellState) {
        // setup your cell depends on state
        switch state {
        case .nonState:
            print("nonState") //update cell to default state
        case .playing:
            songArtwork.image = UIImage(named: "Play")
        case .paused:
            songArtwork.image = UIImage(named: "Pause")
        }
    }
}

/ / / TableViewController

 // use for track cell state, for playing dynamic image usage
    func stateForCell(at indexPath: IndexPath) -> SongData.PlayingCellState {
        // when firstly open the tab song list/app(with no song played), do not attach playing state image
        if SongData.songList.count == 0 {
            return .nonState
        } else {
            if indexPath.row == SongData.currentTrack {
                return SongData.isPlaying ? .playing : .paused
            } else {
                return .nonState
            }
        }
    }

    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
            // return cell
        } 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
        }

        cell.config(forState: stateForCell(at: indexPath))
        return cell
    }

enter image description here

/// Update, finally I make it worked, to involve lottie-ios library, and import it in CustomCell.swift, implement it in playAnimation(), but the pity thing is that animation repeat mode is not working, the animation just repeat once even I set the loopMode. I will search what is wrong later.

import UIKit
import Lottie

class CustomCell: UITableViewCell {

    @IBOutlet weak var songTitle: UILabel!
    @IBOutlet weak var songArtist: UILabel!
    @IBOutlet weak var songArtwork: UIImageView!
    @IBOutlet weak var view: UIView!
    @IBOutlet weak var addButton: UIButton!

    let animationView = AnimationView()

    override func awakeFromNib() {
        super.awakeFromNib()
        songArtwork.layer.cornerRadius = 8.0
    }

    func playAnimation(){
        let animation = Animation.named("366-equalizer-bounce")
        animationView.animation = animation
        // weird thing is that animation repeat is not working here...
        animationView.loopMode = LottieLoopMode.repeat(3600.0)
        animationView.play()

        animationView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(animationView)

        NSLayoutConstraint.activate([
            animationView.heightAnchor.constraint(equalTo: view.heightAnchor),
            animationView.widthAnchor.constraint(equalTo: view.widthAnchor)
        ])
    }

    func config(forState state: SongData.PlayingCellState) {

        // setup your cell depends on state
        switch state {
        case .nonState:
            print("nonState")
            view.isHidden = true
        case .playing:
            view.isHidden = false
            playAnimation()
        case .paused:
            view.isHidden = false
            // to set this latter 
            // songArtwork.image = UIImage(named: "Pause")
        }
    }
}

Upvotes: 2

Views: 654

Answers (1)

ATV
ATV

Reputation: 367

  1. For the implementing of:

"Is that a GIF image used or other dynamic image?" - You can choose any of the options below that is more preferable for you:


  1. Changing of the cell's state:

    //e.g. add it to your presenter or wherever you are storing info about `currentTrack`
    ...
    enum PlayingCellState {
        case default
        case playing
        case paused
        ...
    }
    ...
    func stateForCell(at indexPath: IndexPath) -> PlayingCellState {
        if indexPath.row == SongData.currentTrack {
            return isPlaying? .playing : .paused
        } else {
            return .default
        } 
    }
    
    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
            return cell
        } 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
        }
    
        cell.config(forState: stateForCell(at: indexPath)
    }
    
    //add to your CustomCell 
    func config(forState state: PlayingCellState) {
    // setup your cell depends on state
    }
    

Upvotes: 1

Related Questions