zoukankan      html  css  js  c++  java
  • 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("
    ")
            // 解析每一行
            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(" ") 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 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() } } }



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

  • 相关阅读:
    leetcode 309. Best Time to Buy and Sell Stock with Cooldown
    leetcode 714. Best Time to Buy and Sell Stock with Transaction Fee
    leetcode 32. Longest Valid Parentheses
    leetcode 224. Basic Calculator
    leetcode 540. Single Element in a Sorted Array
    leetcode 109. Convert Sorted List to Binary Search Tree
    leetcode 3. Longest Substring Without Repeating Characters
    leetcode 84. Largest Rectangle in Histogram
    leetcode 338. Counting Bits
    git教程之回到过去,版本对比
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6872870.html
Copyright © 2011-2022 走看看