将事件传递给 UITableView 之外的 UITableViewCell
Pass events to UITableViewCell outside of UITableView
我有一个应用程序可以在 UITableView
上显示播客剧集列表。每个单元格都使用扩展 UITableViewCell
的自定义 class 进行管理,并且每个单元格都有自己的 AVAudioPlayer
实例来控制剧集的播放。我要做的是下一个:
当我点击播放一集时,如果有另一集在播放,则停止它,然后开始新的。
我为实现这一点所做的是在 UITableViewCell
上创建一个协议,只要按下播放按钮就会触发一个事件。然后在我的 UIViewController
上实施该协议并使用 cellForRowAt
获取最新选择的单元格(我保留对最新选择的 IndexPath
的引用)并调用暂停方法。这似乎可行,但后来我意识到它只有在屏幕上显示两个单元格时才有效。每当我想获得一个不在屏幕上的带有 cellForRowAt
的单元格时,方法 returns null 并且我无法更新该单元格,这会导致两个单元格同时播放声音。
这是我的单元格代码:
@IBAction func playbackButtonHandler(_ sender: UIButton) {
guard let audioPlayer = self.player else {
self.downloadAudio(forPodcast: podcast.id)
return
}
guard let cellIndex = indexPath else { return }
if (audioPlayer.isPlaying) {
audioPlayer.pause()
delegate?.onPauseActionSelected(forRow: cellIndex)
} else {
audioPlayer.play()
delegate?.onPlayActionSelected(forRow: cellIndex)
}
sender.isSelected = !sender.isSelected
}
和 ViewController:
func onPlayActionSelected(forRow row: IndexPath) {
if let activeItem = self.activePodcast {
if row != activeItem {
guard let activeCell = self.tableView.cellForRow(at: activeItem) as? PodcastCell else { return }
activeCell.playbackButtonHandler(activeCell.playbackButton)
}
}
self.activePodcast = row
}
有更好的方法吗?
编辑:
尝试了 Larme 的建议并在 ViewController 中为 AVAudioController
创建了一个单例,它解决了同时播放两个音轨的问题。但是,这仍然留下了如何更新单元格控件的问题,因为暂停按钮仍然可见,就好像它仍在播放音频一样。
请参阅图片进行说明:
我有一个单元格不再在屏幕上播放音频。然后我点击第一个单元格上的播放。音频在第一个单元格停止并开始播放
现在我滚动到底部,虽然单元格不再播放,但暂停按钮仍然可见。我需要一种方法来调用单元格来更改该按钮的状态
所以解决了2个问题中的一个,即同时播放2个音频。现在第二个问题,就是刷新UI。您应该在正在播放音频的单元格中显示暂停按钮,而播放按钮将替换上次播放的单元格中的暂停按钮。
现在您不需要在 onPlayActionSelected 方法中调用 cellForRow。而是将代码写入 tableview 的 cellForRowAt 委托方法中。因为如果该单元格不可见,您不需要立即更改前一个单元格的暂停按钮,只有当用户向下滚动到该位置时,您才需要将暂停按钮更改为播放按钮,因此用户不会看到差异.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let activeCell = /* Deque your tableViewCell with its subclass */
if let activeItem = self.activePodcast {
if indexPath.row == activeItem {
activeCell.buttonImageView.image = UIImage(named: "Play")!
}else {
activeCell.buttonImageView.image = UIImage(named: "Pause")!
}
}
return activeCell
}
我有一个应用程序可以在 UITableView
上显示播客剧集列表。每个单元格都使用扩展 UITableViewCell
的自定义 class 进行管理,并且每个单元格都有自己的 AVAudioPlayer
实例来控制剧集的播放。我要做的是下一个:
当我点击播放一集时,如果有另一集在播放,则停止它,然后开始新的。
我为实现这一点所做的是在 UITableViewCell
上创建一个协议,只要按下播放按钮就会触发一个事件。然后在我的 UIViewController
上实施该协议并使用 cellForRowAt
获取最新选择的单元格(我保留对最新选择的 IndexPath
的引用)并调用暂停方法。这似乎可行,但后来我意识到它只有在屏幕上显示两个单元格时才有效。每当我想获得一个不在屏幕上的带有 cellForRowAt
的单元格时,方法 returns null 并且我无法更新该单元格,这会导致两个单元格同时播放声音。
这是我的单元格代码:
@IBAction func playbackButtonHandler(_ sender: UIButton) {
guard let audioPlayer = self.player else {
self.downloadAudio(forPodcast: podcast.id)
return
}
guard let cellIndex = indexPath else { return }
if (audioPlayer.isPlaying) {
audioPlayer.pause()
delegate?.onPauseActionSelected(forRow: cellIndex)
} else {
audioPlayer.play()
delegate?.onPlayActionSelected(forRow: cellIndex)
}
sender.isSelected = !sender.isSelected
}
和 ViewController:
func onPlayActionSelected(forRow row: IndexPath) {
if let activeItem = self.activePodcast {
if row != activeItem {
guard let activeCell = self.tableView.cellForRow(at: activeItem) as? PodcastCell else { return }
activeCell.playbackButtonHandler(activeCell.playbackButton)
}
}
self.activePodcast = row
}
有更好的方法吗?
编辑:
尝试了 Larme 的建议并在 ViewController 中为 AVAudioController
创建了一个单例,它解决了同时播放两个音轨的问题。但是,这仍然留下了如何更新单元格控件的问题,因为暂停按钮仍然可见,就好像它仍在播放音频一样。
请参阅图片进行说明:
我有一个单元格不再在屏幕上播放音频。然后我点击第一个单元格上的播放。音频在第一个单元格停止并开始播放
现在我滚动到底部,虽然单元格不再播放,但暂停按钮仍然可见。我需要一种方法来调用单元格来更改该按钮的状态
所以解决了2个问题中的一个,即同时播放2个音频。现在第二个问题,就是刷新UI。您应该在正在播放音频的单元格中显示暂停按钮,而播放按钮将替换上次播放的单元格中的暂停按钮。
现在您不需要在 onPlayActionSelected 方法中调用 cellForRow。而是将代码写入 tableview 的 cellForRowAt 委托方法中。因为如果该单元格不可见,您不需要立即更改前一个单元格的暂停按钮,只有当用户向下滚动到该位置时,您才需要将暂停按钮更改为播放按钮,因此用户不会看到差异.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let activeCell = /* Deque your tableViewCell with its subclass */
if let activeItem = self.activePodcast {
if indexPath.row == activeItem {
activeCell.buttonImageView.image = UIImage(named: "Play")!
}else {
activeCell.buttonImageView.image = UIImage(named: "Pause")!
}
}
return activeCell
}