Это сложно объяснить, не зная больше об остальной части приложения. Важно дать немного больше контекста. Я постараюсь дать вам ответ, предполагая определенные вещи.
Сначала я предположу, что у вас есть Song
объекты, которые выглядят так:
public struct Song: Equatable {
let name: String
let fileName: String
}
Ваша база данных имеет следующие открытые методы и свойства:
class DB {
func getSong(_ position: Int) -> Song?
func getPosition(_ song: Song) -> Int?
var count: Int
}
Чтобы упростить этот пример кода на init
, некоторые предварительно определенные данные инициализируются.
Также существует объект Player
, который управляет воспроизведением аудио следующими открытыми методами:
class Player {
func currentlyPlaying() -> Song?
func play(this song: Song)
func stop()
}
Теперь с помощью этого ранее определенного я создал настраиваемую ячейку для отображения имени и кнопки для каждого Song
в базе данных. Определение таково:
class CustomCell : UITableViewCell {
@IBOutlet weak var label: UILabel!
@IBOutlet weak var button: UIButton!
}
И выглядит так:
![Prototype custom cell](https://i.stack.imgur.com/wzO8J.png)
Далее давайте определим методы источника данных tableview. В каждой ячейке добавляется цель для события touchUpInside каждой кнопки (как вы это определили в вопросе).
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return DB.shared.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell",
for: indexPath) as! CustomCell
cell.label.text = DB.shared.getSong(indexPath.row)!.name
cell.button.addTarget(self, action: #selector(buttonTapped(_:)),
for: .touchUpInside)
return cell
}
Далее давайте определим вспомогательный метод для определения местоположения UIVIew
внутри TableView
. С помощью этого метода мы можем получить IndexPath
любого элемента управления внутри любой ячейки в TableView
. Возвращаемое значение является необязательным для возврата nil
, если не найдено.
func getViewIndexInTableView(tableView: UITableView, view: UIView) -> IndexPath? {
let pos = view.convert(CGPoint.zero, to: tableView)
return tableView.indexPathForRow(at: pos)
}
Был определен еще один вспомогательный метод для изменения изображения кнопки с анимацией:
func changeButtonImage(_ button: UIButton, play: Bool) {
UIView.transition(with: button, duration: 0.4,
options: .transitionCrossDissolve, animations: {
button.setImage(UIImage(named: play ? "Play" : "Stop"), for: .normal)
}, completion: nil
}
Был необходим метод, чтобы остановить любую текущую воспроизводимую песню. Прежде всего, проверьте, играет ли песня, если это так, вызовите метод stop Player
. Затем давайте локализуем позицию Song
в базе данных, которая в моем случае соответствует позиции в TableView
; Имея это, давайте создадим IndexPath для получения соответствующей ячейки, наконец, вызовем changeButtonImage
с кнопкой ячейки, чтобы изменить изображение.
func stopCurrentlyPlaying() {
if let currentSong = Player.shared.currentlyPlaying() {
Player.shared.stop()
if let indexStop = DB.shared.getPosition(currentSong) {
let cell = tableView.cellForRow(at: IndexPath(item: indexStop, section: 0)) as! CustomCell
changeButtonImage(cell.button, play: true)
}
}
}
Метод buttonTapped
, который начинает воспроизведение песни, имеет некоторую логику внутри. Во-первых, для использования в методе addTarget
сигнатуре метода необходимо @objc
. Логика следующая:
- Локализовать кнопку
IndexPath
в табличном представлении, используя вспомогательный метод.
- Локализация песни в базе данных, номер строки в таблице соответствует порядку в базе данных.
- Если в данный момент воспроизводится песня, которая совпадает с локализованной для нажатой кнопки, это означает, что мы просто хотим остановить песню, поэтому вызывается
stopCurrentlyPlaying
и метод возвращается.
- Если это не та же песня или ничего не воспроизводится, давайте позвоним:
stopCurrentlyPlaying
, начните воспроизведение новой песни и измените изображение нажатой кнопки на Стоп.
Код выглядит так:
@objc func buttonTapped(_ sender: UIButton) {
// Let's localize the index of the button using a helper method
// and also localize the Song i the database
if let index = getViewIndexInTableView(tableView: tableView, view: sender),
let song = DB.shared.getSong(index.row) {
// If a the song located is the same it's currently playing just stop
// playing it and return.
guard song != Player.shared.currentlyPlaying() else {
stopCurrentlyPlaying()
return
}
// Stop any playing song if necessary
stopCurrentlyPlaying()
// Start playing the tapped song
Player.shared.play(this: song)
// Change the tapped button to a Stop image
changeButtonImage(sender, play: false)
}
}
Вот небольшое видео работы примера приложения: образец приложения