I have been struggling with 2 issues for the last 2 weeks and couldn't find the solution yet, working on an audio player where I want to play the audio files when the UItableview cell clicked or the button inside clicks on the play button So I created a struct with Audio details which I later plan to extract from mp3 files like song name, artist duration, etc. but right now I hard code these details so that my main focus is to play a song on cell tap or button
struct Audio {
let id: Int
let trackName: String
let trackTitle: String
let creationDate = Date()
let album: String
let uploadedBy: String
let genre: String
let lyricsLang: String
let artist: String
let duration: Float
var completed = false
}
Problems
I want to hide the play button if the user clicks the other cell only that cell which is playing the current song will show the button (it's for either play or stop) but the problem are buttons shows on each row of the cell also I don't want to hide the button if I click the playing song cell again.
If the user taps on cell, based on cell number it'll always play the same song and I want to play songs like 0.mp3, 1.mp3, 2.mp3, 3.mp3 based on what is the cell number, and the stop button is not working if I tried to stop the song before I play the next song or tried to leave the cell Below is my whole code
class AudioListViewController: UIViewController { var selectedRowIndex = -1 var songList: [Audio] = [ Audio(id: 0, trackName: "Song 1", trackTitle: "ABbcd:", album: "Loreim loreim", uploadedBy: "A men", genre: "Romantic", lyricsLang: "English", artist: "God", duration: 2.00), Audio(id: 1, trackName: "Song 2", trackTitle: "ABbcd:", album: "Loreim loreim", uploadedBy: "A men", genre: "Romantic", lyricsLang: "English", artist: "God", duration: 2.00), Audio(id: 2, trackName: "Song 3", trackTitle: "ABbcd:", album: "Loreim loreim", uploadedBy: "A men", genre: "Romantic", lyricsLang: "English", artist: "God", duration: 2.00) ] @IBOutlet weak var songListTableView: UITableView! var isTapped: Bool = false @IBOutlet weak var close: UIButton! override func viewDidLoad() { super.viewDidLoad() songListTableView.dataSource = self songListTableView.delegate = self title = "Back" navigationItem.backButtonTitle = "Back be?" songListTableView.register(UINib(nibName: "SongsListTableViewCell", bundle: nil), forCellReuseIdentifier: "SongListCell") } @IBAction func closeSe(_ sender: Any) { self.dismiss(animated: true, completion: nil) } } extension AudioListViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return songList.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "SongListCell", for: indexPath) as! SongsListTableViewCell cell.songTitle?.text = songList[indexPath.row].trackName cell.songDuration?.text = String(songList[indexPath.row].duration) return cell } } extension AudioListViewController: UITableViewDelegate{ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let position = indexPath.row print(indexPath.row) let vc = tableView.dequeueReusableCell(withIdentifier: "SongListCell", for: indexPath) as! SongsListTableViewCell vc.songs = songList vc.position = position let selectedFilterRow = songList[indexPath.section].id if selectedFilterRow == indexPath.row { return } if let previousCell = tableView.cellForRow(at: IndexPath(row: selectedFilterRow, section: indexPath.section)) { vc.useSong.isHidden = true vc.useSong.alpha = 0 vc.stopSong() } if let cell = tableView.cellForRow(at: indexPath) { vc.useSong.isHidden = true vc.useSong.alpha = 0 vc.stopSong() vc.configure(position: position) } } }
Now to get the song file name on tap, and other feature of cell
class SongsListTableViewCell: UITableViewCell {
public var songs: [Audio] = [
Audio(id: 0, trackName: "Song 1", trackTitle: "ABbcd:", album: "Loreim loreim",
uploadedBy: "A men", genre: "Romantic", lyricsLang: "English", artist: "God",
duration: 2.00),
Audio(id: 1, trackName: "Song 2", trackTitle: "ABbcd:", album: "Loreim loreim",
uploadedBy: "A men", genre: "Romantic", lyricsLang: "English", artist: "God",
duration: 2.00),
Audio(id: 2, trackName: "Song 3", trackTitle: "ABbcd:", album: "Loreim loreim",
uploadedBy: "A men", genre: "Romantic", lyricsLang: "English", artist:
"God", duration: 2.00) ]
public var position: Int = 0
public var isPlaying: Bool = false
var cellsState: Bool = false
var songPlayer: AVAudioPlayer?
@IBOutlet weak var singleViewCell: UIStackView!
@IBOutlet weak var songCellView: UIView!
@IBOutlet weak var songImage: UIImageView!
@IBOutlet weak var songTitle: UILabel!
@IBOutlet weak var songDuration: UILabel!
@IBOutlet weak var makeFavorite: UIButton!
@IBOutlet weak var useSong: UIButton!
let songReoad: AudioListViewController! = nil
override func awakeFromNib() {
super.awakeFromNib()
useSong.addTarget(self, action:
#selector(SongsListTableViewCell.selectSong(_:)), for: .touchUpInside)
makeFavorite.addTarget(self, action:
#selector(SongsListTableViewCell.makeFavourite(_:)), for: .touchUpInside )
useSong.isHidden = true
}
private let albumNameLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.numberOfLines = 0 // line wrap
return label
}()
private let artistNameLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.numberOfLines = 0 // line wrap
return label
}()
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
useSong.layer.cornerRadius = 6
configure(position: self.position)
}
func configure(position:Int) {
let song = songs[position]
let songId = String(song.id)
let urlString = Bundle.main.path(forResource: songId, ofType: "mp3")
do {
try AVAudioSession.sharedInstance().setMode(.default)
try AVAudioSession.sharedInstance().setActive(true, options:
.notifyOthersOnDeactivation)
guard let urlString = urlString else {
return
}
songPlayer = try AVAudioPlayer(contentsOf: URL(string: urlString)!)
guard let player = songPlayer else {
return
}
player.volume = 0.5
player.play()
isPlaying = true
}
catch {
print("error occurred")
}
songTitle.text = song.trackName
albumNameLabel.text = song.album
// Frame
let yPosition = artistNameLabel.frame.origin.y + 70 + 20
let size: CGFloat = 70
backButton.frame = CGRect(x: 20,
y: yPosition,
width: size,
height: size)
// Add actions
makeFavorite.addTarget(self, action: #selector(didTapPlayPauseButton), for:
.touchUpInside)
}
func stopSong(){
if let player = songPlayer {
player.stop()
}else{
songPlayer?.stop()
}
}
@IBAction func selectSong(_ sender: UIButton) {
cellsState = !cellsState
songPlayer?.stop()
if (cellsState) {
useSong.isHidden = false
useSong.alpha = 1
UIView.animate(withDuration: 0.6,
animations: {
self.useSong.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)
},
completion: { _ in
UIView.animate(withDuration: 0.6) {
self.useSong.transform = CGAffineTransform.identity
}
})
} else {
useSong.isHidden = true
useSong.alpha = 0
}
}
@IBAction func makeFavourite(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
makeFavorite.setImage(UIImage(systemName: "star.fill"), for: .normal)
} else {
makeFavorite.setImage(UIImage(systemName: "star"), for: .normal)
}
}
@objc func didTapPlayPauseButton() {
if songPlayer?.isPlaying == true {
// pause
songPlayer?.pause()
}
else {
// play
songPlayer?.play()
}
}
}
This is how it's looking right now SongList view
This is my Songlistview songlistview