Swift版音乐播放器(简化版),swift音乐播放器
這幾天閑著也是閑著,學(xué)習(xí)一下Swift的,于是到開(kāi)源社區(qū)Download了個(gè)OC版的音樂(lè)播放器,練練手,在這里發(fā)揚(yáng)開(kāi)源精神,
希望對(duì)大家有幫助!
這個(gè)DEMO里,使用到了
AudioPlayer(對(duì)音頻封裝的庫(kù))
FreeStreamer(老外寫(xiě)的音頻高效處理庫(kù))
LKDBHelper(將數(shù)據(jù)模型直接寫(xiě)到數(shù)據(jù)庫(kù)中的庫(kù))
AFNetworking (網(wǎng)絡(luò)庫(kù))
SDWebImage (圖片獲取庫(kù))
另外,我也把OC版的ProgressHUD轉(zhuǎn)成了Swift版本的HYBProgressHUD,希望對(duì)大家有用啊!
目前只實(shí)現(xiàn)了這幾個(gè)簡(jiǎn)單的功能,希望有時(shí)間且愛(ài)研究的同學(xué),追加更多的功能再開(kāi)源出來(lái)哦!
下面我說(shuō)一下封裝的網(wǎng)絡(luò)請(qǐng)求類(lèi):
import Foundation/// 請(qǐng)求成功與失敗的回調(diào) typealias requestSuccessCloser = (responseObject: AnyObject?) ->Void typealias failCloser = (error: NSError?) ->Void/// /// 描述:網(wǎng)絡(luò)請(qǐng)求基礎(chǔ)類(lèi),所有GET請(qǐng)求方式都是以GET開(kāi)頭的類(lèi)方法,POST請(qǐng)求方式會(huì)以POST開(kāi)頭命名類(lèi)方法 /// /// 作者:huangyibiao class HYBBaseRequest: NSObject {struct BaseURL {static var baseURL: String = kServerBase}////// 描述:解析JSON數(shù)據(jù)////// 參數(shù):jsonObject 網(wǎng)絡(luò)請(qǐng)求獲取下來(lái)數(shù)據(jù)////// 返回:如果解析成功,返回字典,否則返回nilclass func parseJSON(#jsonObject: AnyObject?) ->NSDictionary? {if let result = jsonObject as? NSDictionary {return result}return nil}////// 描述: GET請(qǐng)求方式////// 參數(shù): serverPath --請(qǐng)求路徑,不包含基礎(chǔ)路徑/// success --請(qǐng)求成功時(shí)的回調(diào)閉包/// fail --請(qǐng)求失敗時(shí)的回調(diào)閉包////// 返回: AFHTTPRequestOperation類(lèi)型對(duì)象,外部可以通過(guò)引用此對(duì)象實(shí)例,在需要取消請(qǐng)求時(shí),調(diào)用cancel()方法class func GETRequest(serverPath: String, success: requestSuccessCloser, fail: failCloser) ->AFHTTPRequestOperation {var op = manager().GET(serverPath, parameters: nil, success: { (op, responseObject) -> Void insuccess(responseObject: responseObject)}, failure: { (op, error) -> Void infail(error: error)})return op}class func downloadFile(serverPath: String, success: requestSuccessCloser, fail: failCloser) ->AFHTTPRequestOperation {var op = AFHTTPRequestOperation(request: NSURLRequest(URL: NSURL(string: String(format: "%@%@", kServeBase1, serverPath))))op.setCompletionBlockWithSuccess({ (requestOp, responseObject) -> Void insuccess(responseObject: responseObject)}, failure: { (requestOP, error) -> Void infail(error: error)})op.start()return op}////// 私有方法區(qū)///private class func manager() ->AFHTTPRequestOperationManager {var manager = AFHTTPRequestOperationManager(baseURL: NSURL(string: BaseURL.baseURL))manager.requestSerializer.setValue("application/json", forHTTPHeaderField: "Accept")manager.requestSerializer.setValue("application/json", forHTTPHeaderField: "content-type")manager.requestSerializer.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Accept")manager.requestSerializer.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")// 設(shè)置響應(yīng)頭支持的格式manager.responseSerializer.acceptableContentTypes = NSSet(array: ["application/json", "application/javascript", "application/lrc", "application/x-www-form-urlencoded"])return manager} }
因?yàn)橘Y源類(lèi)型不同,所以要在請(qǐng)求頭添加支持的格式才能訪(fǎng)問(wèn)到資源哦。
下面是封裝歌詞顯示的UI,這里沒(méi)有細(xì)化對(duì)時(shí)間的把握,只是粗略實(shí)現(xiàn)功能,有時(shí)間的同學(xué)可以對(duì)播放進(jìn)度把握得更好!
import Foundation/// /// 描述: 顯示歌詞控件 /// /// 作者: huangyibiao class HYBSongLRCView: UIView {private var scrollView: UIScrollView!private var keyArray = NSMutableArray()private var titleArray = NSMutableArray()private var lineLabelArray = NSMutableArray()private var currentPlayingLineTime: float_t = 0.0////// 重寫(xiě)父類(lèi)的方法///override init(frame: CGRect) {super.init(frame: frame)self.scrollView = UIScrollView(frame: CGRectMake(0, 10, self.width(), self.height() - 20))// 暫時(shí)關(guān)閉可交互功能self.scrollView.userInteractionEnabled = falseself.addSubview(self.scrollView)}required init(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}////// public方法區(qū)///////// 描述:解析歌詞////// 參數(shù):lrcPath LRC歌詞的路徑func parseSong(lrcPath: String) {self.keyArray.removeAllObjects()self.titleArray.removeAllObjects()var content = NSString(contentsOfFile: lrcPath, encoding: NSUTF8StringEncoding, error: nil)var array = content.componentsSeparatedByString("\n")// 解析每一行for line in array {if let lrcLine = line as? NSString {if lrcLine.length != 0 {self.parseLRCLine(lrcLine)}}}self.bubbleSortLrcLines(self.keyArray)self.scrollView.contentOffset = CGPointZeroself.scrollView.contentSize = CGSizeMake(scrollView.width(), CGFloat(keyArray.count * 25))self.configureLRCLineLabels()}////// 描述:移除顯示歌詞的標(biāo)簽func removeAllSubviewsInScrollView() {for subview in self.scrollView.subviews {subview.removeFromSuperview()}self.lineLabelArray.removeAllObjects()}////// 描述:移除之前的歌詞數(shù)據(jù)func clearLRCContents() {self.keyArray.removeAllObjects()self.titleArray.removeAllObjects()}////// 描述:指定歌詞播放的時(shí)間,會(huì)根據(jù)時(shí)間滾動(dòng)到對(duì)應(yīng)的歌詞行////// 參數(shù):time 歌詞行播放的時(shí)間func moveToLRCLine(#time: NSString) {if self.keyArray.count != 0 {var currentTimeValue = self.timeToFloat(time)var index = 0var hasFound = falsefor index = 0; index < self.keyArray.count; index++ {if let lrcTime = self.keyArray[index] as? NSString {var tmpTimeValue = self.timeToFloat(lrcTime)if fabs(tmpTimeValue - currentTimeValue) <= fabs(0.000000001) {hasFound = truecurrentPlayingLineTime = tmpTimeValuebreak}}}if hasFound || (!hasFound && currentPlayingLineTime < currentTimeValue) {if index < self.lineLabelArray.count {if let label = self.lineLabelArray[index] as? UILabel {updateCurrentTimeLRC(label)self.scrollView.setContentOffset(CGPointMake(0.0, 25.0 * CGFloat(index)),animated: true)}}}}}////// private方法區(qū)///////// 描述:解析歌詞行////// 參數(shù):lrcLine 該行歌詞private func parseLRCLine(lrcLine: NSString) {if lrcLine.length == 0 {return}var array = lrcLine.componentsSeparatedByString("\n")for var i = 0; i < array.count; i++ {var tempString = array[i] as NSStringvar lineArray = tempString.componentsSeparatedByString("]")for var j = 0; j < lineArray.count - 1; j++ {var line = lineArray[j] as NSStringif line.length > 8 {var str1 = tempString.substringWithRange(NSMakeRange(3, 1))var str2 = tempString.substringWithRange(NSMakeRange(6, 1))if str1 == ":" && str2 == "." {var lrc = lineArray.last as NSStringvar time = lineArray[j].substringWithRange(NSMakeRange(1, 8)) as NSString// 時(shí)間作為KEYself.keyArray.addObject(time.substringToIndex(5))// 歌詞會(huì)為值self.titleArray.addObject(lrc)}}}}}////// 描述:對(duì)所有歌詞行進(jìn)行冒泡排序////// 參數(shù):array 要進(jìn)行冒泡排序的數(shù)組private func bubbleSortLrcLines(array: NSMutableArray) {for var i = 0; i < array.count; i++ {var firstValue = self.timeToFloat(array[i] as NSString)for var j = i + 1; j < array.count; j++ {var secondValue = self.timeToFloat(self.keyArray[j] as NSString)if firstValue > secondValue {array.exchangeObjectAtIndex(i, withObjectAtIndex: j)self.titleArray.exchangeObjectAtIndex(i, withObjectAtIndex: j)}}}}////// 描述:把時(shí)間字符串轉(zhuǎn)換成浮點(diǎn)值////// 參數(shù):time 時(shí)間字符串,格式為:"05:11"private func timeToFloat(time: NSString) ->float_t {var array = time.componentsSeparatedByString(":")var result: NSString = "\(array[0])"if array.count >= 2 {result = "\(array[0]).\(array[1])"}return result.floatValue}////// 描述:創(chuàng)建顯示歌詞的標(biāo)簽private func configureLRCLineLabels() {self.removeAllSubviewsInScrollView()for var i = 0; i < titleArray.count; i++ {var title = titleArray[i] as Stringvar label = UIMaker.label(CGRectMake(0.0,25.0 * CGFloat(i) + scrollView.height() / 2.0,scrollView.width(),25.0),title: title)label.textColor = UIColor.lightGrayColor()label.font = UIFont.systemFontOfSize(14.0)scrollView.addSubview(label)lineLabelArray.addObject(label)}}////// 描述:更新當(dāng)前顯示的歌詞private func updateCurrentTimeLRC(currentLabel: UILabel) {for label in self.lineLabelArray {if let item = label as? UILabel {if item == currentLabel {item.textColor = kNavColoritem.font = UIFont.boldSystemFontOfSize(16.0)} else {item.textColor = UIColor.lightGrayColor()item.font = UIFont.systemFontOfSize(14.0)}}}} }Swift版的HYBProgressHUD控件,調(diào)用方式是非常簡(jiǎn)單的,使用的都是公開(kāi)的類(lèi)方法調(diào)用方式:
import Foundation import UIKit/// /// @brief 樣式 enum HYBProgressHUDStyle {case BlackHUDStyle /// 黑色風(fēng)格case WhiteHUDStyle /// 白色風(fēng)格 }/// /// @brief 定制顯示通知的視圖HUD /// @author huangyibiao class HYBProgressHUD: UIView {var hud: UIToolbar?var spinner: UIActivityIndicatorView?var imageView: UIImageView?var titleLabel: UILabel?////// private 屬性///private let statusFont = UIFont.boldSystemFontOfSize(16.0)private var statusColor: UIColor!private var spinnerColor: UIColor!private var bgColor: UIColor!private var successImage: UIImage!private var errorImage: UIImage!////// @brief 單例方法,只允許內(nèi)部調(diào)用private class func sharedInstance() ->HYBProgressHUD {struct Instance {static var onceToken: dispatch_once_t = 0static var instance: HYBProgressHUD?}dispatch_once(&Instance.onceToken, { () -> Void inInstance.instance = HYBProgressHUD(frame: UIScreen.mainScreen().bounds)Instance.instance?.setStyle(HYBProgressHUDStyle.WhiteHUDStyle)})return Instance.instance!}override init(frame: CGRect) {super.init(frame: frame)hud = nilspinner = nilimageView = niltitleLabel = nilself.alpha = 0.0}required init(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}////// 公開(kāi)方法////// 顯示信息class func show(status: String) {sharedInstance().configureHUD(status, image: nil, isSpin: true, isHide: false)}/// 顯示成功信息class func showSuccess(status: String) {sharedInstance().configureHUD(status, image: sharedInstance().successImage, isSpin: false, isHide: true)}/// 顯示出錯(cuò)信息class func showError(status: String) {sharedInstance().configureHUD(status, image: sharedInstance().errorImage, isSpin: false, isHide: true)}/// 隱藏class func dismiss() {sharedInstance().hideHUD()}////// 私有方法///////// @brief 創(chuàng)建并配置HUDprivate func configureHUD(status: String?, image: UIImage?, isSpin: Bool, isHide: Bool) {configureProgressHUD()/// 標(biāo)題if status == nil {titleLabel!.hidden = true} else {titleLabel!.text = status!titleLabel!.hidden = false}// 圖片if image == nil {imageView?.hidden = true} else {imageView?.hidden = falseimageView?.image = image}// spinif isSpin {spinner?.startAnimating()} else {spinner?.stopAnimating()}rotate(nil)addjustSize()showHUD()if isHide {NSThread.detachNewThreadSelector("hideWhenTimeout", toTarget: self, withObject: nil)}}////// @brief 設(shè)置風(fēng)格樣式,默認(rèn)使用的是黑色的風(fēng)格,如果需要改成白色的風(fēng)格,請(qǐng)?jiān)趦?nèi)部修改樣式private func setStyle(style: HYBProgressHUDStyle) {switch style {case .BlackHUDStyle:statusColor = UIColor.whiteColor()spinnerColor = UIColor.whiteColor()bgColor = UIColor(white: 0, alpha: 0.8)successImage = UIImage(named: "ProgressHUD.bundle/success-white.png")errorImage = UIImage(named: "ProgressHUD.bundle/error-white.png")breakcase .WhiteHUDStyle:statusColor = UIColor.whiteColor()spinnerColor = UIColor.whiteColor()bgColor = UIColor(red: 192.0 / 255.0, green: 37.0 / 255.0, blue: 62.0 / 255.0, alpha: 1.0)successImage = UIImage(named: "ProgressHUD.bundle/success-white.png")errorImage = UIImage(named: "ProgressHUD.bundle/error-white.png")breakdefault:break}}////// @brief 獲取窗口windowprivate func getWindow() ->UIWindow {if let delegate: UIApplicationDelegate = UIApplication.sharedApplication().delegate {if let window = delegate.window {return window!}}return UIApplication.sharedApplication().keyWindow}////// @brief 創(chuàng)建HUDprivate func configureProgressHUD() {if hud == nil {hud = UIToolbar(frame: CGRectZero)hud?.barTintColor = bgColorhud?.translucent = truehud?.layer.cornerRadius = 10hud?.layer.masksToBounds = true/// 監(jiān)聽(tīng)設(shè)置方向變化NSNotificationCenter.defaultCenter().addObserver(self,selector: "rotate:",name: UIDeviceOrientationDidChangeNotification,object: nil)}if hud!.superview == nil {getWindow().addSubview(hud!)}if spinner == nil {spinner = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)spinner!.color = spinnerColorspinner!.hidesWhenStopped = true}if spinner!.superview == nil {hud!.addSubview(spinner!)}if imageView == nil {imageView = UIImageView(frame: CGRectMake(0, 0, 28, 28))}if imageView!.superview == nil {hud!.addSubview(imageView!)}if titleLabel == nil {titleLabel = UILabel(frame: CGRectZero)titleLabel?.backgroundColor = UIColor.clearColor()titleLabel?.font = statusFonttitleLabel?.textColor = statusColortitleLabel?.baselineAdjustment = UIBaselineAdjustment.AlignCenterstitleLabel?.numberOfLines = 0titleLabel?.textAlignment = NSTextAlignment.CentertitleLabel?.adjustsFontSizeToFitWidth = false}if titleLabel!.superview == nil {hud!.addSubview(titleLabel!)}}////// @brief 釋放資源private func destroyProgressHUD() {NSNotificationCenter.defaultCenter().removeObserver(self, name: UIDeviceOrientationDidChangeNotification, object: nil)titleLabel?.removeFromSuperview()titleLabel = nilspinner?.removeFromSuperview()spinner = nilimageView?.removeFromSuperview()imageView = nilhud?.removeFromSuperview()hud = nil}////// @brief 設(shè)置方向變化通知處理func rotate(sender: NSNotification?) {var rotation: CGFloat = 0.0switch UIApplication.sharedApplication().statusBarOrientation {case UIInterfaceOrientation.Portrait:rotation = 0.0breakcase .PortraitUpsideDown:rotation = CGFloat(M_PI)breakcase .LandscapeLeft:rotation = -CGFloat(M_PI_2)breakcase .LandscapeRight:rotation = CGFloat(M_PI_2)breakdefault:break}hud?.transform = CGAffineTransformMakeRotation(rotation)}////// @brief 調(diào)整大小private func addjustSize() {var rect = CGRectZerovar width: CGFloat = 100.0var height: CGFloat = 100.0/// 計(jì)算文本大小if titleLabel!.text != nil {var style = NSMutableParagraphStyle()style.lineBreakMode = NSLineBreakMode.ByCharWrappingvar attributes = [NSFontAttributeName: statusFont, NSParagraphStyleAttributeName: style.copy()]var option = NSStringDrawingOptions.UsesLineFragmentOriginvar text: NSString = NSString(CString: titleLabel!.text!.cStringUsingEncoding(NSUTF8StringEncoding)!,encoding: NSUTF8StringEncoding)rect = text.boundingRectWithSize(CGSizeMake(160, 260), options: option, attributes: attributes, context: nil)rect.origin.x = 12rect.origin.y = 66width = rect.size.width + 24height = rect.size.height + 80if width < 100 {width = 100rect.origin.x = 0rect.size.width = 100}}hud!.center = CGPointMake(kScreenWidth / 2, kScreenHeight / 2)hud!.bounds = CGRectMake(0, 0, width, height)var h = titleLabel!.text == nil ? height / 2 : 36imageView!.center = CGPointMake(width / 2, h)spinner!.center = CGPointMake(width / 2, h)titleLabel!.frame = rect}////// @brief 顯示private func showHUD() {if self.alpha == 0.0 {self.alpha = 1.0hud!.alpha = 0.0self.hud!.transform = CGAffineTransformScale(self.hud!.transform, 1.4, 1.4)UIView.animateKeyframesWithDuration(0.15,delay: 0.0,options: UIViewKeyframeAnimationOptions.AllowUserInteraction,animations: { () -> Void inself.hud!.transform = CGAffineTransformScale(self.hud!.transform, 1.0 / 1.4, 1.0 / 1.4)self.hud!.alpha = 1.0}, completion: { (isFinished) -> Void in})}}////// @brief 隱藏private func hideHUD() {if self.alpha == 1.0 {UIView.animateKeyframesWithDuration(0.2,delay: 0.0,options: UIViewKeyframeAnimationOptions.AllowUserInteraction,animations: { () -> Void inself.hud!.transform = CGAffineTransformScale(self.hud!.transform, 0.35, 0.35)self.hud!.alpha = 0.0}, completion: { (isFinished) -> Void inself.destroyProgressHUD()self.alpha = 0.0})}}////// @brief 在指定時(shí)間內(nèi)隱藏func hideWhenTimeout() {autoreleasepool { () -> () invar length = countElements(self.titleLabel!.text!)var sleepTime: NSTimeInterval = NSTimeInterval(length) * 0.04 + 0.5NSThread.sleepForTimeInterval(sleepTime)self.hideHUD()}} }剩下的部分, 就需要有耐心的同學(xué)們?nèi)パ芯看a了,點(diǎn)擊這里可以下載到源代碼
?
最精簡(jiǎn)版的音樂(lè)播放器
與50位技術(shù)專(zhuān)家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的Swift版音乐播放器(简化版),swift音乐播放器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 运用@media实现网页自适应中的几个关
- 下一篇: fdisk 磁盘分区命令