Reputation: 41
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.
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
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
Reputation: 505
Try calling playSound(file: String?)
in collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
Find the image from the selected cell
Upvotes: -1