标签:
//** 实现一种动画效果 */
override func scrollViewDidScroll(scrollView: UIScrollView) {
//获取指定的cell
guard let indexRows = tableView.indexPathsForVisibleRows else {
return
}
//** 获取中间的cell */
let firstCell = indexRows.first?.row ?? 0
let lastCell = indexRows.last?.row ?? 0
//** 计算中间的cell */
let middleCell = Int(Float(firstCell + lastCell) * 0.5)
//** 遍历指定的所有的cell */
for indexRow in indexRows {
//取出cell
let cell = tableView.cellForRowAtIndexPath(indexRow)
cell?.x = CGFloat(abs(indexRow.row - middleCell) * 40)
print(indexRow.row - middleCell)
}
}
//** 歌曲名称 */
@IBOutlet weak var nameLabel: UILabel!
//** 歌手名称 */
@IBOutlet weak var singerLabel: UILabel!
//** 总音乐时间 */
@IBOutlet weak var totalLabel: UILabel!
//** 歌手背景图片 */
@IBOutlet weak var singerImageView: UIImageView!
//** 能让现实歌词的view拖动的scrollView */
@IBOutlet weak var lrcSImageView: UIScrollView!
//** 歌手专辑图片 */
@IBOutlet weak var backImageView: UIImageView!
//** 暂停或者播放 */
@IBOutlet weak var playOrPause: UIButton!
//** 当前时间 */
@IBOutlet weak var currentLabel: UILabel!
//** 显示歌词的label */
@IBOutlet weak var lrcLabel: UILabel!
//** 滑块 */
@IBOutlet weak var silderProgress: UISlider!
//** 继续播放音乐 */
func playMusic() {
player?.play()
}
//** 暂停播放 */
func pauseMusic() {
player?.pause()
}
//** 创建音乐播放列表 (XFJQQMusicListItem: 音乐列表的模型)*/
var musicList : [XFJQQMusicListItem]?
//** 提供一个记录歌曲的索引 */
var index = 0 {
didSet {
//判断
if index < 0 {
index = (musicList?.count ?? 0) - 1
}
if index > ((musicList?.count ?? 0) - 1){
index = 0
}
}
}
class XFJQQMusicNewMessageModel: NSObject {
//* 让该模型拥有显示歌单的模型 /
var QQMusicItem : XFJQQMusicListItem?
//* 当前播放的时间 /
var costTime : NSTimeInterval = 0
//* 总播放的时间 /
var totalTime : NSTimeInterval = 0
//** 提供当前时间和总时间的get方法 */
var costFormatTime : String {
get{
return XFJQQTimeTool.getTime(costTime)
}
}
//** 提供总时间的get方法 */
var totalFormatTime : String {
get{
return XFJQQTimeTool.getTime(totalTime)
}
}
//** 播放的状态 */
var isPlaying : Bool = false
}
//** 设置一个方法用来提供最新的数据 */
func getQQMusicNewMessage() ->XFJQQMusicNewMessageModel {
//** 给暂时歌词中的模型属性赋值,保持最新的数据 */
QQMusicMessageModel.QQMusicItem = musicList![index]
//** 当前播放的进度 */
QQMusicMessageModel.costTime = tool.player?.currentTime ?? 0
//** 歌曲的总时长 */
QQMusicMessageModel.totalTime = tool.player?.duration ?? 0
//** 播放状态 */
QQMusicMessageModel.isPlaying = tool.player?.playing ?? false
//** 返回最新的数据模型 */
return QQMusicMessageModel
}
//设置一个方法对音乐的处理
func playMusic(musicM : XFJQQMusicListItem) {
//取出模型中的音乐文件名
let fileName = musicM.filename ?? ""
//传入音乐文件名播放音乐
tool.playMusic(fileName)
//** 判断如果列表中没有音乐就直接返回 */
if musicList == nil {
return
}
//** 并且记录当前的音乐索引 */
index = (musicList?.indexOf(musicM))!
}
//** 重新播放 */
func playCurrentMusic() ->() {
tool.playMusic()
}
//** 暂停播放 */
func pauseCurrentMusic() {
tool.pauseMusic()
}
//** 上一首 */
func preMusic() {
//索引递减
index -= 1
//判断
if let muiscM = musicList {
//取出模型
let music = muiscM[index]
//播放音乐
playMusic(music)
}
}
//** 下一首 */
func nextMusic() {
//索引增加
index += 1
//判断
if let musicM = musicList {
//取出模型
let music = musicM[index]
//播放
playMusic(music)
}
}
class XFJQQTimeTool: NSObject {
class func getTime(time : NSTimeInterval) ->String {
let min = Int(time / 60)
let sec = Int(time) % 60
//** 转成字符串 */
let resultStr = String(format: "%02d:%02d", min,sec)
//** 返回结果 */
return resultStr
}
}
//** 设置一次 */
private func setUpOnce() {
setUpViewOnce()
setUpSilder()
}
//** 设置多次 */
private func setUpTimes() {
setUpViewFrame()
setUpForeImage()
}
//** 只需要设置一次的数据 */
private func setUpDataTime() ->() {
let musicMessageModel = XFJQQMusicOperationTool.shareInstance.getQQMusicNewMessage()
//** 歌曲名称 */
nameLabel.text = musicMessageModel.QQMusicItem?.name
//** 歌手背景图片 */
singerImageView.image = UIImage(named: (musicMessageModel.QQMusicItem?.icon ?? ""))
//** 歌手专辑图片 */
backImageView.image = UIImage(named: (musicMessageModel.QQMusicItem?.icon)!)
//** 歌手名称 */
singerLabel.text = musicMessageModel.QQMusicItem?.singer
//** 歌曲总时间 */
totalLabel.text = "\(musicMessageModel.totalFormatTime)"
}
//** 设置多次的数据 */
func setUpDatasTimes() {
let musicMessageModel = XFJQQMusicOperationTool.shareInstance.getQQMusicNewMessage()
//** 当前播放时间 */
currentLabel.text = "\(musicMessageModel.costFormatTime)"
//** 进度条 */
silderProgress.value = Float(musicMessageModel.costTime / musicMessageModel.totalTime)
//** 播放状态 */
playOrPause.selected = musicMessageModel.isPlaying
}
//** 播放和暂停 */
@IBAction func playAndPause(button : UIButton)
{
//判断
button.selected = !button.selected
if button.selected {
XFJQQMusicOperationTool.shareInstance.playCurrentMusic()
}else{
XFJQQMusicOperationTool.shareInstance.pauseCurrentMusic()
}
}
//** 上一首 */
@IBAction func preButton()
{
let operationTool = XFJQQMusicOperationTool.shareInstance
//调用播放上一首的方法
operationTool.preMusic()
setUpDataTime()
}
//** 下一首 */
@IBAction func nextButton()
{
let operationTool = XFJQQMusicOperationTool.shareInstance
operationTool.nextMusic()
setUpDataTime()
}
@IBAction func popVC()
{
navigationController?.popViewControllerAnimated(true)
}
//** 设置定时器 */
func addTimer() {
//** 设置定时器 */
timer = NSTimer(timeInterval: 1, target: self, selector: "setUpDatasTimes", userInfo: nil, repeats: true)
//** 将定时器添加到主运行循环中 */
NSRunLoop.currentRunLoop().addTimer(timer!, forMode: NSRunLoopCommonModes)
}
//** 移除定时器 */
func removeTimer() ->() {
timer?.invalidate()
timer = nil
}
extension CALayer {
// 暂停动画
func pauseAnimate()
{
let pausedTime: CFTimeInterval = convertTime(CACurrentMediaTime(), fromLayer: nil)
speed = 0.0;
timeOffset = pausedTime;
}
// 恢复动画
func resumeAnimate()
{
let pausedTime: CFTimeInterval = timeOffset
speed = 1.0;
timeOffset = 0.0;
beginTime = 0.0;
let timeSincePause: CFTimeInterval = convertTime(CACurrentMediaTime(), fromLayer: nil) - pausedTime
beginTime = timeSincePause;
}
}
//恢复动画
private func resumeAnimation() {
foreImageView.layer.resumeAnimate()
}
//暂停动画
private func pauseAnimation() {
foreImageView.layer.pauseAnimate()
}
private func addAnimation() {
//移除上移个动画
foreImageView.layer.removeAnimationForKey("rotation")
//添加动画
let animation = CABasicAnimation(keyPath: "transform.rotation.z")
//设置相关属性
animation.duration = 30
animation.fromValue = 0
animation.toValue = M_PI * 2
animation.repeatCount = MAXFLOAT
//播放完成后不需要移除动画
animation.removedOnCompletion = false
//添加动画
foreImageView.layer.addAnimation(animation, forKey: "rotation")
}
//** 播放和暂停 */
@IBAction func playAndPause(button : UIButton)
{
button.selected = !button.selected
//判断
if button.selected {
XFJQQMusicOperationTool.shareInstance.pauseCurrentMusic()
pauseAnimation()
}else {
XFJQQMusicOperationTool.shareInstance.playCurrentMusic()
resumeAnimation()
}
}
//将歌词的数据源交给展示歌曲的控制器来展示
lrcTVC.dataSource = lrcMs
//切换歌曲开始动画
addAnimation()
//判断如果是选择暂停和开始的属性做相应的动画
if musicMessageModel.isPlaying {
resumeAnimation()
}else {
pauseAnimation()
}
class XFJQQLrcModel: NSObject {
//** 歌词演唱的开始时间 */
var beginTime : NSTimeInterval = 0
//** 歌词演唱的结束时间 */
var endTime : NSTimeInterval = 0
//** 歌词的内容 */
var lrcStr : String = ""
}
//提供一个方法对某一行歌词的返回(需要传入当前播放的时间进度和模型中的开始时间,结束时间)
//采用元组的方式来达到读取歌词的经度
class func getLrcMusicRow(current : NSTimeInterval, lrcModel : [XFJQQLrcModel]) ->(row :Int, lrcM : XFJQQLrcModel){
//取出模型的个数
let count = lrcModel.count
//遍历
for i in 0..<count {
let lrcM = lrcModel[i]
//判断时间区间
if lrcM.beginTime < current && lrcM.endTime > current {
return (i, lrcM)
}
}
return (0, XFJQQLrcModel())
}
[ti:]
[ar:]
[al:]
//设计一个方法用来处理歌词
class func getLrcMusicData(fileName : String?) ->[XFJQQLrcModel] {
//获取歌词文件的路径
guard let path = NSBundle.mainBundle().pathForResource(fileName, ofType: nil) else{
return [XFJQQLrcModel]()
}
//加载文件的内容
var contentLrc = ""
do {
contentLrc = try String(contentsOfFile: path)
}catch {
print(error)
return [XFJQQLrcModel]()
}
//将歌词转成一行一行组成的数组
let lrcArray = contentLrc.componentsSeparatedByString("\n")
//创建一个装XFJQQLrcModel这种类型的数组
var lrcMs = [XFJQQLrcModel]()
//遍历歌词的组成的数组,然后放入lrcMs数组中
for lrcmStr in lrcArray {
//过滤掉垃圾数据
if lrcmStr.containsString("[ti:") || lrcmStr.containsString("[ar:") || lrcmStr.containsString("[al:") {
continue
}
//装入上面的数组中
let lrcm = XFJQQLrcModel()
lrcMs.append(lrcm)
[00:00.89]传奇
[00:02.34]作词:刘兵
[00:03.82]作曲:李健
[00:05.48]演唱:王菲
//拿到的数据才是真正能解析的数据
//替换
let resultStr = lrcmStr.stringByReplacingOccurrencesOfString("[", withString: "")
//开始解析
let timeAndContent = resultStr.componentsSeparatedByString("]")
if timeAndContent.count == 2 {
let time = timeAndContent[0]
lrcm.beginTime = XFJQQTimeTool.getLrcFormatTime(time)
let content = timeAndContent[1]
lrcm.lrcStr = content
}
}
//遍历所有的数组中的时间
let count = lrcMs.count
for i in 0..<count {
if i != count - 1 {
lrcMs[i].endTime = lrcMs[i + 1].beginTime
}
}
//返回处理好的时间和歌词
return lrcMs
}
}
//** 该方法是对歌词的开唱时间和结束时间的处理(根据传入的字符串,返回一个确切的时间) */
class func getLrcFormatTime(time : String) ->NSTimeInterval {
//根据":"取出时间
let minAndSec = time.componentsSeparatedByString(":")
//判断
if minAndSec.count == 2 {
//分钟
let min = NSTimeInterval(minAndSec[0]) ?? 0
//秒钟
let sec = NSTimeInterval(minAndSec[1]) ?? 0
//返回处理好的时间
return min * 60 + sec
}
//如果走到这里,就直接返回0
return 0
}
//获取歌词数据源
let lrcMs = XFJQQMusicLrcDataTool.getLrcMusicData(musicMessageModel.musicModel?.lrcname)
//打印出歌词
print(lrcMs)
//将歌词的数据源交给展示歌曲的控制器来展示
lrcTVC.dataSource = lrcMs
///MARK : - 数据源方法
extension XFJQQLrcTVC {
//组
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
//每组的cell
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//由模型数据决定
return dataSource.count
}
//每行cell的内容
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//用该方法得到cell
let cell = XFJQQMusicLrcCell.getMusicLrcCell(tableView)
//判断如果当前处在最中间的是正在播放的行数,那么久赋值,否则就赋值为0
if indexPath.row == scrollRow {
cell.progress = progress
}else {
cell.progress = 0.0
}
//取出模型
let lrcStr = dataSource[indexPath.row]
//赋值
cell.lrcStr = lrcStr.lrcStr
return cell
}
}
@IBOutlet weak var lrcLabel: XFJQQMusicLrcLabel!
//提供一个属性给展示歌词的view中的歌词状态
var progress : Double = 0.0 {
didSet {
lrcLabel.progress = progress
}
}
var lrcStr : String = "" {
didSet {
lrcLabel.text = lrcStr
}
}
}
///MARK : - 再累扩展中提供一个方法,返回cell
extension XFJQQMusicLrcCell {
class func getMusicLrcCell(tableView : UITableView) ->XFJQQMusicLrcCell {
let lrcCellID = "lrcCell"
var cell = tableView.dequeueReusableCellWithIdentifier(lrcCellID) as? XFJQQMusicLrcCell
if cell == nil {
cell = NSBundle.mainBundle().loadNibNamed("XFJQQMusicLrcCell", owner: nil, options: nil).first as? XFJQQMusicLrcCell
}
return cell!
}
}
class XFJQQMusicLrcLabel: UILabel {
//自定义更新歌词的进度(提供set方法)
var progress : Double = 0.0 {
didSet {
//重绘
setNeedsDisplay()
}
}
override func drawRect(rect: CGRect) {
super.drawRect(rect)
//设置填充颜色
UIColor.greenColor().set()
let progressloat = CGFloat(progress)
let rect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width * progressloat, rect.size.height)
UIRectFillUsingBlendMode(rect, CGBlendMode.SourceIn)
}
}
var dataSource : [XFJQQLrcModel] = [XFJQQLrcModel]() {
didSet {
tableView.reloadData()
}
}
//设置歌词滚动到中间(set方法)
var scrollRow : Int = 0 {
didSet {
//判断防止重复滚动(用旧值作为判断)
if scrollRow != oldValue {
tableView.reloadRowsAtIndexPaths(tableView.indexPathsForVisibleRows!, withRowAnimation: UITableViewRowAnimation.Fade)
let indexPath = NSIndexPath(forRow: scrollRow, inSection: 0)
//拿到角标滚动到哪个位置
tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)
//刷新(如果先做动画再刷新的话,动画还没做完就直接刷新了,会出现显示歌词的view跳动,所以需要先刷新再动画)
// tableView.reloadRowsAtIndexPaths(tableView.indexPathsForVisibleRows!, withRowAnimation: UITableViewRowAnimation.Fade)
}
}
}
var progress : Double = 0.0 {
didSet {
//获取当前正在行号
let indexPath = NSIndexPath(forRow: scrollRow, inSection: 0)
//将当前的cell类型转换
let cell = tableView.cellForRowAtIndexPath(indexPath) as? XFJQQMusicLrcCell
//给cell中progress赋值
cell?.progress = progress
}
}
//在view将要布局的时候对显示歌词的view布局,让其头部显示在中间
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
tableView.contentInset = UIEdgeInsets(top: tableView.height * 0.5, left: 0, bottom: tableView.height * 0.5, right: 0)
}
//更新滚动的时候歌词(调用频率频繁)
func updateLrc () ->() {
//获取歌曲的最新值
let musicMessageModel = XFJQQMusicOperationTool.shareInstance.getUpNewMusicMessage()
//获取最新歌词的行号
let rowLrm = XFJQQMusicLrcDataTool.getLrcMusicRow(musicMessageModel.costTime, lrcModel:lrcTVC.dataSource)
let row = rowLrm.row
//赋值
lrcTVC.scrollRow = row
//给歌词标签展示歌词
let lrcm = rowLrm.lrcM
lrcLabel.text = lrcm.lrcStr
//歌词进度(当前的进度除以在总进度)
let value = (musicMessageModel.costTime - lrcm.beginTime) / (lrcm.endTime - lrcm.beginTime)
//赋值
lrcLabel.progress = value
//给展示歌词的view赋值
lrcTVC.progress = value
标签:
原文地址:http://blog.csdn.net/xf931456371/article/details/51503433