zoukankan      html  css  js  c++  java
  • Swift版音乐播放器(简化版),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控件,调用方式是非常简单的,使用的都是公开的类方法调用方式:

    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()
            }
        }
    }


    剩下的部分, 就需要有耐心的同学们去研究代码了,点击这里可以下载到源代码

    最精简版的音乐播放器

  • 相关阅读:
    Nginx internal 指令限制访问图片资源文件
    Laravel 5 中文文档 CHM 版
    Educational Codeforces Round 89 (Rated for Div. 2)
    Markdown写的第一篇文章,猜猜里边有什么东西吧!
    Git暂存流程
    Java BIO、NIO与AIO的介绍(学习过程)
    如何在Mac中安装telnet
    使用IDEA编译java程序时,出现的编译错误: error:java:错误:不支持发行版本5
    Java中请优先使用try-with-resources而非try-finally
    Redis入门学习(学习过程记录)
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/5053880.html
Copyright © 2011-2022 走看看