Swift版音樂播放器(簡化版)
來源:程序員人生 發布時間:2014-11-24 08:22:51 閱讀次數:2633次
這幾天閑著也是閑著,學習1下Swift的,因而到開源社區Download了個OC版的音樂播放器,練練手,在這里發揚開源精神,
希望對大家有幫助!
這個DEMO里,使用到了
AudioPlayer(對音頻封裝的庫)
FreeStreamer(老外寫的音頻高效處理庫)
LKDBHelper(將數據模型直接寫到http://www.vxbq.cn/db/中的庫)
AFNetworking (網絡庫)
SDWebImage (圖片獲得庫)
另外,我也把OC版的ProgressHUD轉成了Swift版本的HYBProgressHUD,希望對大家有用啊!






目前只實現了這幾個簡單的功能,希望有時間且愛研究的同學,追加更多的功能再開源出來哦!
下面我說1下封裝的網絡要求類:
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 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()
}
}
}
剩下的部份, 就需要有耐心的同學們去研究代碼了,點擊這里可以下載到源代碼
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈