这几天闲着也是闲着,学习一下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 网络请求获取下来数据////// 返回:如果解析成功,返回字典,否则返回nilclass 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 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}////// 私有方法区///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 = falseself.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 = CGPointZeroself.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 = 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方法区///////// 描述:解析歌词行////// 参数: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// 时间作为KEYself.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 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)}}////// 描述:更新当前显示的歌词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控件,调用方式是非常简单的,使用的都是公开的类方法调用方式:

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 = 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")}////// 公开方法////// 显示信息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 创建并配置HUDprivate 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 = falseimageView?.image = image}// spinif 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")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 创建HUDprivate func configureProgressHUD() {if hud == nil {hud = UIToolbar(frame: CGRectZero)hud?.barTintColor = bgColorhud?.translucent = truehud?.layer.cornerRadius = 10hud?.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 = 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 设置方向变化通知处理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 调整大小private func addjustSize() {var rect = CGRectZerovar width: CGFloat = 100.0var height: CGFloat = 100.0/// 计算文本大小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 在指定时间内隐藏func hideWhenTimeout() {autoreleasepool { () -> () invar length = countElements(self.titleLabel!.text!)var sleepTime: NSTimeInterval = NSTimeInterval(length) * 0.04 + 0.5NSThread.sleepForTimeInterval(sleepTime)self.hideHUD()}}
}

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

最精简版的音乐播放器

Swift版音乐播放器(简化版),swift音乐播放器相关推荐

  1. swift版QQ音乐播放器(二)

    一 完善部分的QQ音乐效果图 二 需要完善点 1 歌曲的切换和暂停播放 2 歌曲当前播放时间和歌曲总时间的更新 3 进度条的处理 4 歌手头像处理 5 头像动画效果 6 歌词的进度显示 8 完善细节 ...

  2. swift版QQ音乐播放器(一)

    一 部分功能图(后面会完善) 二 讲解思路 1 项目目录结构搭建 2 抽取工具类 3 自定义cell 4 分层思想 5 业务逻辑 三 项目目录搭建和相关配置 1 采用搭建搭建结构思路 : MCV模式 ...

  3. python 循环播放音乐_基于python实现音乐播放器代码实例

    核心播放模块(pygame内核) import time import pygame import easygui as gui file = r'D:\CloudMusic\G.E.M.邓紫棋,艾热 ...

  4. Linux下的豆瓣FM音乐播放器和虾米音乐播放器

    RT.给大家介绍两个我亲测可以使用的非常流行的网页音乐播放器的本地版. A.doubanFM音乐播放器: 对于喜欢在豆瓣FM下听音乐的同学,对于打开一个网页听音乐,肯定会觉得很麻烦.这里我给大家推荐的 ...

  5. python开发音乐播放器教程,Python挑翻音乐网,GUI实现音乐播放器,无敌Pythoner炼成记!...

    今天几篇博文都是些Python纯干货,有难度大的,也有难度比较低的适合新手的.但无一列外,就是它们都会有源码+视频教程二合一供大家学习.这样的文章有个好处,本人的文章多次遭其它人copy到其它网站,这 ...

  6. 22_Android中的本地音乐播放器和网络音乐播放器的编写,本地视频播放器和网络视频播放器,照相机案例,偷拍案例实现

    1 编写以下案例: 当点击了"播放"之后,在手机上的/mnt/sdcard2/natural.mp3就会播放. 2 编写布局文件activity_main.xml <Line ...

  7. html5在线音乐列表播放器,HTML5列表音乐播放器SMusic

    插件描述:一款基于HTML5.Css3的列表式音乐播放器,包含列表,音量,进度,时间,歌词展示以及模式等功能,不依赖任何库 SMusic使用方法 这是一款基于HTML5以及CSS3的列表式音乐播放器, ...

  8. iOS之基于FreeStreamer的简单音乐播放器(模仿QQ音乐)

    代码地址如下: http://www.demodashi.com/demo/11944.html 天道酬勤 前言 作为一名iOS开发者,每当使用APP的时候,总难免会情不自禁的去想想,这个怎么做的?该 ...

  9. 微软关闭音乐服务器,微软关闭Zune音乐服务 Zune播放器变为MP3

    腾讯科技讯 11月16日消息,据外电报道,下载音乐或者串流播放网络歌曲,但Zune播放器仍可作为音乐继续播放器使用. 微软推出首款Zune音乐播放器和相应的Zune数字音乐服务还要追溯到2006年,但 ...

最新文章

  1. 提审马甲包被拒问题记录
  2. h5 修改title 微信_微信h5网页自定义分享(标题、描述、图标)
  3. 《Dream(梦想)》,无力的我,想放弃的我,深深的问自己,什么是梦想!!!
  4. java8 默认方法_默认方法:Java 8的无名英雄
  5. 【操作系统】实验 生产者-消费者问题解决方案
  6. cx_oracle主备服务器,怎么在Python中使用cx_Oracle模块对Oracle数据库进行操作
  7. 英特尔加入 GPU 战局,终用上 6nm 工艺?
  8. ASP.NET Google Maps Javascript API V3 实战基础篇一检测用户位置
  9. 每日英语:How to say No to other people
  10. [QT入门篇]编程基础知识
  11. 2016年下半年 系统分析师 案例分析真题
  12. c++ 建立MFC应用程序
  13. 弱密码、未授权加固/修复建议
  14. Git 和Bitbucket
  15. 今日恐慌与贪婪指数为24 恐慌程度有所缓解
  16. 容器三把斧之 | namespace原理与实现
  17. html如何设置网页的背景图片,使放大或缩小浏览器时,页面排版和背景可以随浏览器放大缩小而排版不会改变,
  18. 【论文分享】ACL 2020 神经网络的可解释性
  19. 利用PIFU-HD生成自己的三维人体图像
  20. 基于MindSpore的MASS网络实现

热门文章

  1. RRID和CAS是什么?
  2. cellphonedb 及其可视化
  3. Java程序设计语言(基础篇)机械工业出版社 原属第10版
  4. python判断对象是否实例化_python中如何判断class当前有哪些实例?
  5. 用shp制作geoJson格式地图数据(shp convert to geoJson)
  6. 计算机视觉与深度学习 | 基于Matlab双目视觉之深度估计(视频中人到相机的距离)(附源代码)
  7. Matlab | Matlab从入门到放弃(6)——数组
  8. 14个你可能不知道的JavaScript调试技巧
  9. python读取excel送到网页_python+selenium excel中文读取填充到网页
  10. 数据结构与算法(C++)– 二叉查找树(Binary Search Tree )