Swift 4 - Приложение звуковой платы - Назначить несколько тегов кнопок одной кнопке программно? - PullRequest
0 голосов
/ 31 августа 2018

Я постараюсь объяснить это как можно лучше. Я создаю приложение Sound Board. Все программно без StoryBoard. Приложение использует UICollectionView для размещения всех имен кавычек в ячейках. Цитаты также являются кнопками. Каждая ячейка представляет собой кнопку, которая должна соответствовать определенному звуковому файлу WAV.

Я использую звуки звездных войн в качестве теста для приложения - может быть проще, если я опубликую большую часть своего кода.

Я хотел бы назначить тестовый звук "blaster-firing" для имени ячейки "Test Name" и звук "yodalaughing" для имени ячейки "Test Name 2"

У меня есть работающий код и ячейки; Когда вы нажимаете на названия ячеек, он воспроизводит только звук бластера, я знаю, это потому, что у меня есть только 1 кнопка-тег, установленная на button1, эта button1 выполняется для каждой ячейки.

Можно ли создавать разные теги кнопок для связи с созданными мной цитатами? Я не уверен, что лучший способ сделать это.

Вот мой ViewController:

class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

let cellId = "cellId"

 //add different quotes for cells
let quotes = [Quote(name:"Test Name"),
              Quote(name: "Test Name2")]

override func viewDidLoad() {
    super.viewDidLoad()

    collectionView?.backgroundColor = UIColor.darkGray

    navigationItem.title = "Board"
    navigationController?.navigationBar.barTintColor = UIColor(red: 0/255, green: 200/255, blue: 255/255, alpha: 1)

    navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white, NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 20)]

    collectionView?.register(SoundBoardCell.self, forCellWithReuseIdentifier: cellId)

}

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return quotes.count
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SoundBoardCell
    cell.quote = quotes[indexPath.item]
    return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: (view.frame.width / 1) - 16, height: 100)
}

private func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insertForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
}

У меня также есть другой класс под названием SoundBoardCells

class SoundBoardCell: UICollectionViewCell, AVAudioPlayerDelegate {

//let testSoundFiles = ["baster-fire", "yodalaughing"]
var audio1 = AVAudioPlayer()
var audio2 = AVAudioPlayer()

var quote: Quote? {
    didSet {
        guard let quoteName = quote?.name else {return}
        button1.setTitle("\(quoteName)", for: .normal)
    }
}

override init(frame: CGRect) {
    super.init(frame: frame)
    setup()
    setCellShadow()
}

func setCellShadow() {

    self.layer.shadowColor = UIColor.black.cgColor
    self.layer.shadowOffset = CGSize(width: 0, height: 1)
    self.layer.shadowOpacity = 1
    self.layer.shadowRadius = 1.0
    self.layer.masksToBounds = false
    self.clipsToBounds = false
    self.layer.cornerRadius = 3
}

func setup() {
    self.backgroundColor = UIColor.lightGray

    self.addSubview(button1)

    do {
        let audioPlayer1 = Bundle.main.path(forResource: "blaster-firing", ofType: "wav")
        try audio1 = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPlayer1!))
    } catch {
        //ERROR
    }

    do {
        let audioPlayer2 = Bundle.main.path(forResource: "yodalaughing", ofType: "wav")
        try audio2 = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPlayer2!))
    } catch {

    }

    // button setups
    button1.anchor(top: topAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0)

    button1.addTarget(self, action: #selector(buttonClicked(sender:)), for: .touchUpInside)

}
// button creations
let button1: UIButton = {
    let button = UIButton()
    button.tag = 0
    button.layer.cornerRadius = 5
    button.layer.borderColor = UIColor.black.cgColor
    button.layer.borderWidth = 1
    button.setTitle("", for: .normal)
    button.setTitleColor(.cyan, for: .normal)
    button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
    button.frame = CGRect(x: 50, y: 50, width: 150, height: 150)
    return button
}()

@IBAction func buttonClicked(sender: UIButton!) {
   // print(quote!.name! as Any)
    if (sender.tag == 0) {
        audio1.play()
    }
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
   }
}

  struct Quote {
  let name: String?
}

Ответы [ 5 ]

0 голосов
/ 01 сентября 2018

Для временного исправления я использовал версию вроде Brandons. По моему cellForItemAt:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SoundBoardCell
    cell.quote = quotes[indexPath.item]
    cell.button1.tag = indexPath.row // this is the added line
    return cell
}

а для моего buttonClicked

 @IBAction func buttonClicked(sender: UIButton!) {
    if (sender.tag == 0) {
        audio1.play()
    }

    if (sender.tag == 1)  {
        audio2.play()
    }
}

Все еще надеюсь очистить это, используя другие доступные методы, но пока это работает. Когда я добавлю другие файлы WAV, это будет довольно много строк аудио файлов.

0 голосов
/ 31 августа 2018

Как уже отмечали другие, несколько тегов на одной кнопке не могут быть хорошей идеей с точки зрения программирования. Однако, несмотря на то, что говорят, что это невозможно, можно создать что-то подобное. Создать новый класс кнопок

class ButtonWithMultipleTags: UIButton {
    var tags : [int] = [ ]
}

Хотя это не то, что вы пытаетесь сделать. каждая кнопка, созданная в ячейке, является собственным объектом. Таким образом, вы можете установить для каждой кнопки свой собственный тег, а не для одной кнопки требуется несколько тегов. Если вы установите ячейку с indexPath.row от 1 до 3, все остальные кнопки будут по-прежнему иметь тег 0

Но другой способ настроить каждую кнопку на определенный звук будет выглядеть примерно так: в вашем контроллере с представлением вашей коллекции

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SoundBoardCell
     cell.button1.tag = indexPath.row
     cell.button1.addTarget(self, #selector(playAudio(sender:_), .touchDown)
     return cell
 }


 // make an array for your audioSounds
 var audioSounds = [audio1, audio2, audio3]

 // add func for selector that takes from audioquotes
  @objc func playAudio(sender: UIButton){
  audioSounds[sender.tag].play
 }

Возможно, это не лучший способ, но он должен работать. Я нахожусь на моем телефоне, поэтому проверьте на наличие мелких ошибок

0 голосов
/ 31 августа 2018

Несколько предложений.

Во-первых, я бы рекомендовал избегать использования тегов для ссылочных действий. Хотя технически это работает, им может быть немного сложно управлять и отслеживать.

Во-вторых, я бы поставил управление звуком за пределы вашей камеры. Ячейка может отследить, какой тип звука необходимо воспроизвести, но разрешить запуск чего-либо в другом месте.

Например, я мог бы подойти к вашему приложению таким образом.

Давайте определим звук, который мы хотим воспроизвести.

enum AudioClip {
    case blaster
    case yoda
}

Если это приложение для работы с звуковыми картами предоставит пользователю возможность создавать свои собственные, то вам может потребоваться создать другой источник данных. Но для этого примера это будет работать. Я бы добавил это к вашей Quote структуре. Фактически, вы можете определить имя клипа в вашем перечислении как вычисляемое свойство и заменить свою структуру Quote.

Затем создайте AudioManager, который может взять кейс AudioClip и воспроизвести для него определенный аудиоклип.

Это упрощает вашу ячейку, так что ей не нужно управлять логикой для разных аудиоклипов. Буквально просто нужно знать Quote для этой конкретной ячейки. При касании этой ячейки либо ячейка, либо представление коллекции может указать AudioManager воспроизвести этот конкретный аудиоклип.

0 голосов
/ 31 августа 2018

Чтобы ответить на ваш вопрос, нет. У кнопки есть только один тег.

Как и предполагали другие, теги кнопок - довольно хрупкий способ выяснить, какой звук был прослушан.

Лучше выяснить, на какой indexPath отображается ячейка, и использовать это для поиска информации в вашей модели данных. Вы можете получить координаты своей кнопки, преобразовать их в систему координат представления коллекции и использовать метод представления коллекции indexPathForItem(at:), чтобы выяснить, какой indexPath был нажат.

Я также согласен с Джошем, что вы не должны помещать свою звуковую логику в клетки. Сделайте так, чтобы действие кнопки вызывало цель / действие в контроллере представления, где вы используете отправителя, чтобы выяснить, к какому indexPath принадлежит кнопка, найдите этот звук в вашей модели и используйте объект менеджера звука для воспроизведения звука.

0 голосов
/ 31 августа 2018

Поскольку вы используете многократно используемые ячейки представления коллекции, достаточно создать один аудиопроигрыватель для каждой ячейки и передать ей имена звуковых файлов. Попробуйте эту опцию:

  1. В cellForItemAtIndexPath передайте имя звукового файла вместе с кавычкой в ​​ячейку:

    cell.quote = quotes[indexPath.item]<br> cell.soundName = <#yourSoundName#>

  2. В вашей SoundBoardCell создайте только один экземпляр AVAudioPlayer и после установки свойства soundName инициализируйте audio1 содержимым звукового файла.
  3. В методе обработчика кнопок просто выполните audio1.play () без проверки тегов:

    @IBAction func buttonClicked(sender: UIButton!) { audio1.play() }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...