当用户点击UITableViewCell内的播放按钮时如何播放音频文件?比如从Whatsapp聊天消息播放音频,任何开源库都可以节省我的时间吗?
答案 0 :(得分:2)
我创建了你想要的相同模块。我已经设计并创建了自定义表格视图单元格,以便在表格视图中加载我的包中的音乐。
为同一个创建了相应的必需变量。
// Music Related Variables
var musicKeyboardView : UIView!
var arrMusics : [String] = []
var previousAudioSelectedIndexPath : IndexPath!
var audioPlayer : AVAudioPlayer?
根据arrMusics,您可以加载音乐的路径。我正在从bundle中加载它,如下所示:
func fetchMusicFromResource() {
// First remove all music data from array
// This code is required because every time switching keyboard will duplicate data.
self.arrMusics.removeAll()
// Fetch all the files paths from CustomKeyboard Target.
// This code return array of string which contains paths for every resource inside CustomKeyboard.
if let files = try? FileManager.default.contentsOfDirectory(atPath: Bundle.main.bundlePath) {
// Take single file and check if it contains "mp3" string, then add to arrMusic.
// Write this code if you know there are mp3 extension for song.
// We know that resource contains mp3 for music file, so this code will work fine.
// You need to change if this is dynamic, means music file with other extensions.
// Make sure video file name not contains mp3 text, otherwise it will not work or may be crash the app.
// If you will use music library songs, then you don't need this code.
for file in files {
if file.contains("mp3") {
self.arrMusics.append(file)
}
}
// Check if arrMusics contains elements more then 0 then, hide the label and show the table,
// otherwise show label and hide table
if self.arrMusics.count > 0 {
self.tblMusic.isHidden = false
self.lblEmptyMusic.isHidden = true
} else {
self.tblMusic.isHidden = true
self.lblEmptyMusic.isHidden = false
}
// Set table rowHeight and estimatedRowHeight as TableViewAutomaticDimension and reload table.
self.tblMusic.rowHeight = UITableViewAutomaticDimension
self.tblMusic.estimatedRowHeight = UITableViewAutomaticDimension
self.tblMusic.reloadData()
}
}
所以在cellForRowAt indexPath方法中,我正在为playButton添加目标,如下所示:
musicCell.btnPlay.tag = indexPath.row * 10
cell.btnPlay.addTarget(self, action: #selector(musicPlayButtonClicked(sender:)), for: .touchUpInside)
当点击播放按钮时,它将触发musicPlayButtonClicked(发送方:)方法,其中包含以下代码来播放音乐。
@IBAction func musicPlayButtonClicked(sender: UIButton) {
// Take the row by sender.tag / 10.
// Previous we set tag of play button with indexPath.row * 10
// So here we are deviding and get original row index and create indexPath for selected row.
let indexPath = IndexPath(row: sender.tag / 10, section: 0)
// This code check if previousAudioSelectedIndexPath not nil,
// then execute code inside if block
if previousAudioSelectedIndexPath != nil {
// This code check indexPath is equal to previousAudioSelectedIndexPath.
if (indexPath == previousAudioSelectedIndexPath) {
// Set button's selected propery to true.
sender.isSelected = false
// Set previousAudioSelectedIndexPath to nil.
previousAudioSelectedIndexPath = nil
// Call method to play music for selected index.
self.playMusicAt(index: sender.tag)
} else {
// Create cell for previousAudioSelectedIndexPath.
let previousSelectedCell = self.tblMusic.cellForRow(at: previousAudioSelectedIndexPath)
// Take the previousButton selected from previousSelectedCell and Set previousButton's isSelected property to false.
if let previousButton = previousSelectedCell!.contentView.subviews[1] as? UIButton {
previousButton.isSelected = false
}
// Set button's selected propery to true for current selected button.
sender.isSelected = true
// Assign current selected indexPath to previous selected indexPath.
previousAudioSelectedIndexPath = indexPath
// Call method to play music for selected index.
self.playMusicAt(index: sender.tag)
}
} else {
// If current button is selected then stop playing music,
// Otherwise execute code of else block to play music.
if sender.isSelected {
// This code will stop the music for selected row.
sender.isSelected = false
previousAudioSelectedIndexPath = nil
self.playMusicAt(index: sender.tag)
} else {
// This code will start to play the music for selected row.
sender.isSelected = true
previousAudioSelectedIndexPath = indexPath
self.playMusicAt(index: sender.tag)
}
}
}
此代码将用于获取单元格按钮并设置与播放/暂停相关的相应图像。
然后还有一个方法可以创建在从数组获取路径时播放歌曲。请看下面的方法。
func playMusicAt(index: Int) {
// This will check is audioPlayer is not nil and audioPlayer is already playing,
// Then first pause audioPlayer and remove it from memory.
if audioPlayer != nil, (audioPlayer?.isPlaying)! {
audioPlayer?.pause()
audioPlayer = nil
}
// This line of code check previousAudioSelectedIndexPath is not nil,
// then execute code with if block.
if previousAudioSelectedIndexPath != nil {
// This code copy song name from selected index
let songName = self.arrMusics[index / 10].components(separatedBy: ".")
// Create source path of song name with extension.
// If it's failed to create url path,
// then return from this line of code and stop to execute next lines of code.
guard let url = Bundle.main.url(forResource: songName[0], withExtension: "mp3") else { return }
do {
// This will start the AVAudioSession for AVAudioSessionCategoryPlayback.
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
// This code will active AVAudioSession.
try AVAudioSession.sharedInstance().setActive(true)
/* The following line is required for the player to work on iOS 11. Change the file type accordingly*/
audioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
/* iOS 10 and earlier require the following line:
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMP3Layer3) */
// Create new audio player,
// if audio plyer is failed to create,
// then return from this line of code and stop to execute next lines of code.
guard let audioPlayer = audioPlayer else { return }
// This code start playing song
audioPlayer.play()
} catch let error {
// If audio session failed to start or AVAudioPlayer failed to initialised then throw the error.
print(error.localizedDescription)
}
}
}
我希望这段代码可以帮到你。