So I have dynamic tableview and each row have play image. If I select the row image will change to pause icon. But what if I select another row, I need the image on previously selected row to have play icon again.
How to handle such functionality?
All I have is:
class ViewController: UIViewController {
var stations = [
(stationIcon: "rr_icon", stationName: "Radio1", urlString: "http://.._320", isPlaying: false),
(stationIcon: "mm_icon", stationName: "Record2", urlString: "http://../_320", isPlaying: false),
........]
func playSelectedStation(indexPath: NSIndexPath) {
let url = NSURL(string: stations[indexPath.row].urlString)!
stations[indexPath.row].isPlaying = true
avPlayer = AVPlayer(URL: url)
avPlayer.play()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! RadioTableViewCell
cell.playPause.image = stations[indexPath.row].isPlaying ? UIImage(named: "cellPause") : UIImage(named: "cellPlay")
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
switch indexPath.row {
playSelectedStation(indexPath)
tableView.reloadData()
Radio Stations are changing without problem, having issue only with play/pause icon state
You can achieve it by going through visible cells and disable play button in all of them except the one the user has just tapped on:
class PlayItem {
// your code
var isPlaying = false
}
class RadioTableViewCell: UITableViewCell {
// your code ....
func setup(item item: PlayItem) {
image = item.isPlaying ? UIImage(named: "cellPause") : UIImage(named: "cellPlay")
}
}
In your delegate:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! RadioTableViewCell
let item = items[indexPath.row] // you may think of storing this array in some kind of view model
cell.setup(item: item)
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell = tableView.cellForRowAtIndexPath(indexPath) as! RadioTableViewCell
let selectedItem = items[indexPath.row]
selectedItem.isPlaying = !selectedItem.isPlaying
for cell in tableView.visibleCells {
guard let visibleCell = cell as? RadioTableViewCell else { return }
let path = tableView.indexPathForCell(visibleCell)
let item = items[path.row]
item.isPlaying = visibleCell == selectedCell
visibleCell.setup(item: item)
}
}
UPDATE: I have updated my answer to store the playback state in item.
Use the MVC pattern instead of storing data in the view object or the global(view controller) scope. Then your life will be much easier.
I think each row should be backed by a model object. Say:
class PlayItem {
....
var isPlaying = false
}
then your cellForRowAtIndexPath
method:
let playItem = self.playItemArray[indexPath.row]
cell.imageView.image = playItem.isPlaying ? UIImage("cellPause") : UIImage("cellPlay")
then in your didSelectRowAtIndexPath
method, change the selected item isPlaying = true
and all the other items isPlaying = false
, and call tableView.reloadData()
. The table view will refresh all the cells to reflect their correct state.