Swift版音乐播放器(简化版)

这几天闲着也是闲着,学习一下Swift的。于是到开源社区Download了个OC版的音乐播放器,练练手,在这里发扬开源精神。

希望对大家有帮助!

这个DEMO里。使用到了

AudioPlayer(对音频封装的库)

FreeStreamer(老外写的音频高效处理库)

LKDBHelper(将数据模型直接写到数据库中的库)

AFNetworking (网络库)

SDWebImage (图片获取库)

另外。我也把OC版的ProgressHUD转成了Swift版本号的HYBProgressHUD,希望对大家实用啊!










眼下仅仅实现了这几个简单的功能,希望有时间且爱研究的同学,追加很多其它的功能再开源出来哦!


以下我说一下封装的网络请求类:

import Foundation

/// 请求成功与失败的回调
typealias requestSuccessCloser = (responseObject: AnyObject?) ->Void
typealias failCloser = (error: NSError?

) ->Void /// /// 描写叙述:网络请求基础类,全部GET请求方式都是以GET开头的类方法,POST请求方式会以POST开头命名类方法 /// /// 作者:huangyibiao class HYBBaseRequest: NSObject { struct BaseURL { static var baseURL: String = kServerBase } /// /// 描写叙述:解析JSON数据 /// /// 參数:jsonObject 网络请求获取下来数据 /// /// 返回:假设解析成功。返回字典,否则返回nil class func parseJSON(#jsonObject: AnyObject?

) ->NSDictionary? { if let result = jsonObject as? NSDictionary { return result } return nil } /// /// 描写叙述: GET请求方式 /// /// 參数: serverPath --请求路径,不包括基础路径 /// success --请求成功时的回调闭包 /// fail --请求失败时的回调闭包 /// /// 返回: AFHTTPRequestOperation类型对象,外部能够通过引用此对象实例,在须要取消请求时。调用cancel()方法 class func GETRequest(serverPath: String, success: requestSuccessCloser, fail: failCloser) ->AFHTTPRequestOperation { var op = manager().GET(serverPath, parameters: nil, success: { (op, responseObject) -> Void in success(responseObject: responseObject) }, failure: { (op, error) -> Void in fail(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 in success(responseObject: responseObject) }, failure: { (requestOP, error) -> Void in fail(error: error) }) op.start() return op } /// /// 私有方法区 /// 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") // 设置响应头支持的格式 manager.responseSerializer.acceptableContentTypes = NSSet(array: ["application/json", "application/javascript", "application/lrc", "application/x-www-form-urlencoded"]) return manager } }


由于资源类型不同,所以要在请求头加入支持的格式才干訪问到资源哦。


以下是封装歌词显示的UI,这里没有细化对时间的把握,仅仅是粗略实现功能。有时间的同学能够对播放进度把握得更好。

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
    
    ///
    /// 重写父类的方法
    ///
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.scrollView = UIScrollView(frame: CGRectMake(0, 10, self.width(), self.height() - 20))
        // 临时关闭可交互功能
        self.scrollView.userInteractionEnabled = false
        self.addSubview(self.scrollView)
    }
    
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    ///
    /// public方法区
    ///
    
    ///
    /// 描写叙述:解析歌词
    ///
    /// 參数: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 = CGPointZero self.scrollView.contentSize = CGSizeMake(scrollView.width(), CGFloat(keyArray.count * 25)) self.configureLRCLineLabels() } /// /// 描写叙述:移除显示歌词的标签 func removeAllSubviewsInScrollView() { for subview in self.scrollView.subviews { subview.removeFromSuperview() } self.lineLabelArray.removeAllObjects() } /// /// 描写叙述:移除之前的歌词数据 func clearLRCContents() { self.keyArray.removeAllObjects() self.titleArray.removeAllObjects() } /// /// 描写叙述:指定歌词播放的时间,会依据时间滚动到相应的歌词行 /// /// 參数:time 歌词行播放的时间 func moveToLRCLine(#time: NSString) { if self.keyArray.count != 0 { var currentTimeValue = self.timeToFloat(time) var index = 0 var hasFound = false for 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 = true currentPlayingLineTime = tmpTimeValue break } } } 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方法区 /// /// /// 描写叙述:解析歌词行 /// /// 參数: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 NSString var lineArray = tempString.componentsSeparatedByString("]") for var j = 0; j < lineArray.count - 1; j++ { var line = lineArray[j] as NSString if 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 NSString var time = lineArray[j].substringWithRange(NSMakeRange(1, 8)) as NSString // 时间作为KEY self.keyArray.addObject(time.substringToIndex(5)) // 歌词会为值 self.titleArray.addObject(lrc) } } } } } /// /// 描写叙述:对全部歌词行进行冒泡排序 /// /// 參数:array 要进行冒泡排序的数组 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) } } } } /// /// 描写叙述:把时间字符串转换成浮点值 /// /// 參数:time 时间字符串,格式为:"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 } /// /// 描写叙述:创建显示歌词的标签 private func configureLRCLineLabels() { self.removeAllSubviewsInScrollView() for var i = 0; i < titleArray.count; i++ { var title = titleArray[i] as String var 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) } } /// /// 描写叙述:更新当前显示的歌词 private func updateCurrentTimeLRC(currentLabel: UILabel) { for label in self.lineLabelArray { if let item = label as? UILabel { if item == currentLabel { item.textColor = kNavColor item.font = UIFont.boldSystemFontOfSize(16.0) } else { item.textColor = UIColor.lightGrayColor() item.font = UIFont.systemFontOfSize(14.0) } } } } }



Swift版的HYBProgressHUD控件,调用方式是很easy的。使用的都是公开的类方法调用方式:

import Foundation
import UIKit

///
/// @brief 样式
enum HYBProgressHUDStyle {
    case BlackHUDStyle /// 黑色风格
    case WhiteHUDStyle /// 白色风格
}

///
/// @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 单例方法,仅仅同意内部调用 private class func sharedInstance() ->HYBProgressHUD { struct Instance { static var onceToken: dispatch_once_t = 0 static var instance: HYBProgressHUD? } dispatch_once(&Instance.onceToken, { () -> Void in Instance.instance = HYBProgressHUD(frame: UIScreen.mainScreen().bounds) Instance.instance?

.setStyle(HYBProgressHUDStyle.WhiteHUDStyle) }) return Instance.instance! } override init(frame: CGRect) { super.init(frame: frame) hud = nil spinner = nil imageView = nil titleLabel = nil self.alpha = 0.0 } required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } /// /// 公开方法 /// /// 显示信息 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) } /// 显示出错信息 class func showError(status: String) { sharedInstance().configureHUD(status, image: sharedInstance().errorImage, isSpin: false, isHide: true) } /// 隐藏 class func dismiss() { sharedInstance().hideHUD() } /// /// 私有方法 /// /// /// @brief 创建并配置HUD private func configureHUD(status: String?, image: UIImage?

, isSpin: Bool, isHide: Bool) { configureProgressHUD() /// 标题 if status == nil { titleLabel!.hidden = true } else { titleLabel!.text = status! titleLabel!.hidden = false } // 图片 if image == nil { imageView?.hidden = true } else { imageView?.hidden = false imageView?.image = image } // spin if isSpin { spinner?.startAnimating() } else { spinner?.stopAnimating() } rotate(nil) addjustSize() showHUD() if isHide { NSThread.detachNewThreadSelector("hideWhenTimeout", toTarget: self, withObject: nil) } } /// /// @brief 设置风格样式,默认使用的是黑色的风格,假设须要改成白色的风格,请在内部改动样式 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") break case .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") break default: break } } /// /// @brief 获取窗体window private func getWindow() ->UIWindow { if let delegate: UIApplicationDelegate = UIApplication.sharedApplication().delegate { if let window = delegate.window { return window! } } return UIApplication.sharedApplication().keyWindow } /// /// @brief 创建HUD private func configureProgressHUD() { if hud == nil { hud = UIToolbar(frame: CGRectZero) hud?.barTintColor = bgColor hud?.translucent = true hud?.layer.cornerRadius = 10 hud?.layer.masksToBounds = true /// 监听设置方向变化 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 = spinnerColor spinner!.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 = statusFont titleLabel?

.textColor = statusColor titleLabel?.baselineAdjustment = UIBaselineAdjustment.AlignCenters titleLabel?.numberOfLines = 0 titleLabel?.textAlignment = NSTextAlignment.Center titleLabel?

.adjustsFontSizeToFitWidth = false } if titleLabel!.superview == nil { hud!.addSubview(titleLabel!) } } /// /// @brief 释放资源 private func destroyProgressHUD() { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIDeviceOrientationDidChangeNotification, object: nil) titleLabel?.removeFromSuperview() titleLabel = nil spinner?

.removeFromSuperview() spinner = nil imageView?.removeFromSuperview() imageView = nil hud?

.removeFromSuperview() hud = nil } /// /// @brief 设置方向变化通知处理 func rotate(sender: NSNotification?) { var rotation: CGFloat = 0.0 switch UIApplication.sharedApplication().statusBarOrientation { case UIInterfaceOrientation.Portrait: rotation = 0.0 break case .PortraitUpsideDown: rotation = CGFloat(M_PI) break case .LandscapeLeft: rotation = -CGFloat(M_PI_2) break case .LandscapeRight: rotation = CGFloat(M_PI_2) break default: break } hud?.transform = CGAffineTransformMakeRotation(rotation) } /// /// @brief 调整大小 private func addjustSize() { var rect = CGRectZero var width: CGFloat = 100.0 var height: CGFloat = 100.0 /// 计算文本大小 if titleLabel!.text != nil { var style = NSMutableParagraphStyle() style.lineBreakMode = NSLineBreakMode.ByCharWrapping var attributes = [NSFontAttributeName: statusFont, NSParagraphStyleAttributeName: style.copy()] var option = NSStringDrawingOptions.UsesLineFragmentOrigin var 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 = 12 rect.origin.y = 66 width = rect.size.width + 24 height = rect.size.height + 80 if width < 100 { width = 100 rect.origin.x = 0 rect.size.width = 100 } } hud!.center = CGPointMake(kScreenWidth / 2, kScreenHeight / 2) hud!.bounds = CGRectMake(0, 0, width, height) var h = titleLabel!.text == nil ? height / 2 : 36 imageView!.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.0 hud!.alpha = 0.0 self.hud!.transform = CGAffineTransformScale(self.hud!.transform, 1.4, 1.4) UIView.animateKeyframesWithDuration(0.15, delay: 0.0, options: UIViewKeyframeAnimationOptions.AllowUserInteraction, animations: { () -> Void in self.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 in self.hud!.transform = CGAffineTransformScale(self.hud!.transform, 0.35, 0.35) self.hud!.alpha = 0.0 }, completion: { (isFinished) -> Void in self.destroyProgressHUD() self.alpha = 0.0 }) } } /// /// @brief 在指定时间内隐藏 func hideWhenTimeout() { autoreleasepool { () -> () in var length = countElements(self.titleLabel!.text!) var sleepTime: NSTimeInterval = NSTimeInterval(length) * 0.04 + 0.5 NSThread.sleepForTimeInterval(sleepTime) self.hideHUD() } } }



剩下的部分。 就须要有耐心的同学们去研究代码了。点击这里能够下载到源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值