Alicia
Alicia

Reputation: 41

Play Sound From String Arrays Swift

I am trying to play a sound file for each image in a collection view, so if the user taps on an image, the user will hear the name of that image. For example, if the user taps on the image of a cat, the user will hear the sound file, "cat". I have created the collection view of images and a UITapGestureRecognizer was added to the cell. The sound file is played in the imageTapped function at the very bottom of the code, but I do not know how to code this. I don't know what to code after: if tap.state == .recognized, let imageView = tap.view as? UIImageView { The current code in that function builds, but I do not hear a sound when I tap each image. I would really appreciate any help.

Here is a screenshot

class FlashcardsViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource  {

var animals = ["alligator", "bat", "bear", "beaver", "bird", "butterfly", "camel", "cat", "cheetah", "chicken"]

var bodyparts = ["arm", "ear", "eyes", "foot", "hair", "hand", "head", "leg", "mouth", "nose"]

var classroom = ["backpack", "blackboard", "book", "bookshelf", "calculator", "chair", "chalk", "chalkboard", "clock", "colored pencil"]

var clothes = ["belt", "boots", "coat", "dress", "hat", "jeans", "mittens", "pajamas", "pants", "scarf"]

var family = ["baby", "brother", "dad", "family", "grandma", "grandpa", "grandparents", "mom", "parents", "sister"]

var feelings = ["angry", "cold", "confused", "happy", "hot", "hurt", "sad", "scared", "sick", "tired"]

var food = ["apple", "bacon", "banana", "bean", "blackberry", "blueberry", "broccoli", "butter", "carrot", "cereal"]

var house = ["bathtub", "bed", "bowl", "couch", "cup", "dresser", "fridge", "lamp", "mirror", "plant"]

var transportation = ["ambulance", "bike", "boat", "bus", "car", "firetruck", "helicopter", "motorcycle", "police car", "plane"]

var verbs = ["brush your teeth", "carry", "clap", "color", "cook", "crawl", "cut", "dance", "draw", "drink"]

@IBOutlet weak var collectionView: UICollectionView!

@IBOutlet weak var segmentedControl: UISegmentedControl!

var audioPlayer = AVAudioPlayer()

override func viewDidLoad() {
    super.viewDidLoad()

    let tap = UITapGestureRecognizer(target: self, action: #selector(self.imageTapped(tap:)))
    view.addGestureRecognizer(tap)

}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    let arrays = [animals, bodyparts, classroom, clothes, family, feelings, food, house, transportation, verbs]
    let sectionArray = arrays[segmentedControl.selectedSegmentIndex]
    return sectionArray.count

}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell

    let arrays = [animals, bodyparts, classroom, clothes, family, feelings, food, house, transportation, verbs]

    cell.imageView?.image = UIImage(named: arrays[segmentedControl.selectedSegmentIndex][indexPath.row])

    cell.isUserInteractionEnabled = true

    return cell

}

@IBAction func segmentedControlAction(_ sender: Any) {

    collectionView.reloadData()

}

func playSound(file: String?) {

    if let file = file {
        let musicFile = URL(fileURLWithPath: file)

        do{

            try audioPlayer = AVAudioPlayer(contentsOf: musicFile)

            audioPlayer.play()

        }catch{

        }
    }
}
@objc func imageTapped(tap: UITapGestureRecognizer) {

    _ = tap.view as? UIImageView

    print("imageTapped")

    let arrays = [animals, bodyparts, classroom, clothes, family, feelings, food, house, transportation, verbs]
     let sectionArray = arrays[segmentedControl.selectedSegmentIndex]

    if tap.state == .recognized, let imageView = tap.view as? UIImageView {
        for (image) in sectionArray {
            imageView.image = UIImage (named: image)
            if let sound = Bundle.main.path(forResource: image, ofType: "wav") {
                playSound(file: sound)
            }
        }
    }
}

}

Upvotes: 0

Views: 464

Answers (2)

Andrew
Andrew

Reputation: 28539

I think you are making this more complicated than you need to.

Firstly you keep creating your arrays multiple times, there is no need to do this. You could do something like this

var arrays =  [[String]]()

override func viewDidLoad() {
  super.viewDidLoad()

  // populate the array when your view loads
  arrays = [animals, bodyparts, classroom, clothes, family, feelings, food, house, transportation, verbs]

}

That means in your cellForItemAt you do not need to construct it there but you can access the arrays variable that you just created. For UICollectionView you should use indexPath.item instead of indexPath.row, indexPath.row is for UITableViews.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

  let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as CollectionViewCell

  let array = arrays[segmentedControl.selectedSegmentIndex]

  cell.imageView?.image = UIImage(named: array[indexPath.item])

  cell.isUserInteractionEnabled = true

  return cell

}

You also do not need to use a gesture recogniser. UICollectionViews come with a function called didSelectItemAt this is called when you tap your cell. So you could do something like this. You may want to check if a file is already playing before you play the next file.

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  let array = arrays[segmentedControl.selectedSegmentIndex]
  let filename = array[indexPath.item]
  if let filepath = Bundle.main.path(forResource: filename, ofType: "wav") {
    playSound(file: filepath)
  }
}

Also all those arrays that you are creating initially with the filenames, you should declare them as let unless you plan on changing the contents of them. It is more performant to use let than var. var should only be used if you plan on changing the value that is stored.

So change

var animals = ["alligator", "bat", "bear", "beaver", "bird", "butterfly", "camel", "cat", "cheetah", "chicken"]

to

let animals = ["alligator", "bat", "bear", "beaver", "bird", "butterfly", "camel", "cat", "cheetah", "chicken"]

Checkout Apple's documentation for more information about UICollectionViews https://developer.apple.com/documentation/uikit/uicollectionview

Upvotes: 0

mmr118
mmr118

Reputation: 505

Try calling playSound(file: String?) in collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)

Find the image from the selected cell

Upvotes: -1

Related Questions