First I had a couple of UIButtons with a @IBAction to play a sound when tapped. Because I had some problems with constraints on different iPhones I decided to go for a UICollectionView with CustomCells. Now I got this working I want to setup the CustomCells to play a sound when tapped. So I think I will have to setup something like an 'Action' on the custom cells for playing a sound. I do have a 'sort of action' that prints out that the user tapped a custom cell like;
print("tapped tag > ", self.tag)
The original @IBAction I used on a UIButton was:
@IBAction func sound2(_ sender: UIButton) {
sound2.play()
Again, I 'think' I need to setup a sort of action to the CustomCell for playing a sound? And I 'think' I need to declare somewhere what sound to play along with the self.tag? So each customCell will play a different sound..
The only problem, (rookieAlert) I don't know where to start :( But I want to learn! Can somebody point me into the right direction or provide me with some information?
Here is the full code of the project to make things more clear:
import UIKit
import AVFoundation
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
var countries = [UIImage(named:"c1"),UIImage(named:"c2"),UIImage(named:"c3"),UIImage(named:"c4"),UIImage(named:"c5"),UIImage(named:"c6"),UIImage(named:"c7"),UIImage(named:"c8"),UIImage(named:"c9"),UIImage(named:"c10")]
@IBOutlet weak var soundsCollectionView: UICollectionView!
lazy var cv: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 100, height: 100)
var cc = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
cc.translatesAutoresizingMaskIntoConstraints = false
cc.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
cc.delegate = self
cc.dataSource = self
cc.backgroundColor = .black
return cc
}()
let sounds = ["sound1", "sound2", "sound3", "sound4", "sound5"]
var sound1 = AVAudioPlayer()
var sound2 = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.addSubview(cv)
cv.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
cv.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
cv.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
cv.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
// Setting up sound1
do {
sound1 = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "sound1", ofType: "mp3")!))
sound1.prepareToPlay()
} catch {
print(error)
}
// Setting up sound2
do {
sound2 = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "sound2", ofType: "mp3")!))
sound2.prepareToPlay()
} catch {
print(error)
}
}
@IBAction func sound2(_ sender: UIButton) {
if sound2.isPlaying {
sound2.stop()
sound1.stop()
sender.setImage(UIImage(named: "sound1_off.jpg"), for: .normal)
} else {
sound2.play()
sender.setImage(UIImage(named: "sound1_on.jpg"), for: .normal)
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.centerImageView.image = countries[indexPath.row]
cell.tag = indexPath.row
cell.backgroundColor = UIColor.green
return cell
}
//define constant value as per your requirement and declare this variables globally
let inset: CGFloat = 10 //define as per your requirement
let minimumInteritemSpacing: CGFloat = 10 //define as per your requirement
let cellsPerRow = 3
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let marginsAndInsets = inset * 2 + collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right + minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
return .init(width: itemWidth, height: itemWidth)
}
}
class CustomCell: UICollectionViewCell {
lazy var centerImageView: UIImageView = {
var img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.clipsToBounds = true
img.isUserInteractionEnabled = true
img.contentMode = .scaleAspectFill
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handler(_:)))
tapGesture.numberOfTapsRequired = 1
img.addGestureRecognizer(tapGesture)
return img
}()
@objc private func handler(_ sender: UITapGestureRecognizer) {
print("tapped tag > ", self.tag)
}
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(centerImageView)
centerImageView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
centerImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
centerImageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
centerImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
This is for same sound in all cell: try to delete gesture from your centerImage in custom cell, after that add the gesture in cellForItemAt and call the function like this:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.centerImageView.image = countries[indexPath.row]
cell.backgroundColor = UIColor.green
let gesture = UITapGestureRecognizer(target: self, action: #selector(playCellSound))
cell.centerImageView.addGestureRecognizer(gesture)
return cell
}
after that write the func below cellForItemAt:
@objc func playCellSound() {
sound2.play()
print("play sound...")
}
FOR DIFFERENT SOUND IN CELLS:
the number of sounds must be equal the number of countries:
let sounds = ["sound1", "sound2", "sound3", "sound4", "sound5", "sound6", "sound7", "sound8", "sound9", "sound10"]
after that declare your sounds like this:
var sound1 = AVAudioPlayer()
var sound2 = AVAudioPlayer()
var sound3 = AVAudioPlayer()
var sound4 = AVAudioPlayer()
var sound5 = AVAudioPlayer()
var sound6 = AVAudioPlayer()
var sound7 = AVAudioPlayer()
var sound8 = AVAudioPlayer()
var sound9 = AVAudioPlayer()
var sound10 = AVAudioPlayer()
set the other sound like sound 1 and sound 2
now this is your cellForItemAt:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.centerImageView.image = countries[indexPath.row]
cell.backgroundColor = UIColor.green
return cell
}
set numberOfItemsInSection like this:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return countries.count // dynamic number of items based on your countries array
}
implement the method didiSelectItemAt
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let s = sounds[indexPath.item]
switch s {
case "sound1":
sound1.play()
print("s1")
case "sound2":
sound2.play()
print("s2")
case "sound3":
sound3.play()
print("s3")
case "sound4":
sound4.play()
print("s4")
case "sound5":
sound5.play()
print("s5")
case "sound6":
sound6.play()
print("s6")
case "sound7":
sound7.play()
print("s7")
case "sound8":
sound8.play()
print("s8")
case "sound9":
sound9.play()
print("s9")
case "sound10":
sound10.play()
print("s10")
default:
break
}
}
in your custom cell delete tap gesture for centerImageView:
class CustomCell: UICollectionViewCell {
lazy var centerImageView: UIImageView = {
var img = UIImageView()
img.contentMode = .scaleAspectFill
img.clipsToBounds = true
img.isUserInteractionEnabled = true
img.translatesAutoresizingMaskIntoConstraints = false
return img
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(centerImageView)
centerImageView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
centerImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
centerImageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
centerImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
FOR SYSTEM SOUNDS:
replace your var declaration like this:
var sound1: SystemSoundID = 1016
var sound2: SystemSoundID = 1322
var sound3: SystemSoundID = 1110
var sound4: SystemSoundID = 1070
var sound5: SystemSoundID = 1109
var sound6: SystemSoundID = 1117
var sound7: SystemSoundID = 1106
var sound8: SystemSoundID = 1118
var sound9: SystemSoundID = 1256
var sound10: SystemSoundID = 1116
deleting setting up sound 1, 2 etc. and replace the switch case in didSelectItemAt with this:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let s = sounds[indexPath.item]
switch s {
case "sound1":
AudioServicesPlaySystemSound (sound1)
print("s1")
case "sound2":
AudioServicesPlaySystemSound(sound2)
print("s2")
case "sound3":
AudioServicesPlaySystemSound(sound3)
print("s3")
case "sound4":
AudioServicesPlaySystemSound(sound4)
print("s4")
case "sound5":
AudioServicesPlaySystemSound(sound5)
print("s5")
case "sound6":
AudioServicesPlaySystemSound(sound6)
print("s6")
case "sound7":
AudioServicesPlaySystemSound(sound7)
print("s7")
case "sound8":
AudioServicesPlaySystemSound(sound8)
print("s8")
case "sound9":
AudioServicesPlaySystemSound(sound9)
print("s9")
case "sound10":
AudioServicesPlaySystemSound(sound10)
print("s10")
default:
break
}
}
}
this is not the best way but it work fine, it will make you understand how it works and help you to learn
I believe what you are looking for is implementation of the didSelectItemAt
function. You can implement like so by putting with your other collection view functions like cellForItemAt
. Then, make sure the required sound is closely linked with your data source. Meaning you can access the sound you want via indexPath.item
, which is a way of identifying the specific cell that got tapped.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// Use indexPath.item to determine what sound to play
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.