2017.05.22 17:46* 字数 1585 阅读 5095评论 0喜欢 8赞赏 2

学习ios以来差不多接近两个月了,作为一个刚入行的菜鸡终于鼓起勇气写博客并发布出来,本周课程讲到了ios多媒体应用关于音频播放这部分(本菜还在读大学走的移动端ios方向= =),课下作业老师让做个基于AVAudioPlayer的音乐播放器,问题不大,比较简单,想给自己加点难度,最近swift这么火,干脆用swift写个吧!于是逼着自己一点点的边做边啃swift语法,花了差不多3天的时间,粗制滥造 = =!的搞出来个简单版的音乐播放器(希望大家多多指点,供跟我一样刚入行的朋友互相交流,互相学习),如图:

效果图.gif

1.界面

最初想的是该怎么入门,毕竟swift认识我,我不认识它啊!还是去世界上最大的同性交友网站GitHub上去看看有没有关于swift播放器的demo把,从学习别人的代码来入门,结果转了一大圈都没有找到合适的,不过发现了个有四百个star的提供炫酷手势界面壳子的项目,但仅仅是个壳子而已,好吧我的界面就用它了,对了说到界面,他界面用的是StoryBoard还用到了个新控件叫ContainerView,ContainerView是用来在一个视图控制器上添加子视图控制器的,他这样做的好处就是可以让迷你播放栏一只处于界面最上方,点击tabbar切换界面的时候,只需要将ContainerView里的子视图控制器更换即可。具体用法大家可以自行简书。

2.获取音乐及相关信息,封装音乐播放类

界面有了,使用AVAudioPlayer根据本地音乐的路径进行音乐播放,在这里我封装了个方法用来获取本地文件夹myMusic里所有歌曲路径以及作家,封面,歌曲名等。为了做出上一曲下一曲功能我将每首歌曲都编了号。

static func getALL()->Array<Music>{

if musicArry == nil {

var musicArryList=Array<Music>()

var fileArry:[String]?

var num:Int=0;

let path=Bundle.main.path(forResource:"mymusic", ofType: nil)

do{

try fileArry=FileManager.default.contentsOfDirectory(atPath: path!)

}

catch{

print("error")

}

for n in fileArry! {

let singlePath=path!+"/"+n

let avURLAsset = AVURLAsset(url: URL.init(fileURLWithPath: singlePath))

let musicModel:Music = Music()

for i in avURLAsset.availableMetadataFormats {

for j in avURLAsset.metadata(forFormat: i) {

//歌曲名

if j.commonKey == "title"{

musicModel.musicName = j.value as? String

}//封面图片

if j.commonKey == "artwork"{

musicModel.musicimg=j.value as? Data// 这里是个坑坑T T

}//专辑名

if j.commonKey == "albumName"{

musicModel.musicAlbum=j.value as? String

}

//歌手

if j.commonKey == "artist"{

musicModel.musicAuthor=j.value as? String

}

}

}

musicModel.musicURL=URL.init(fileURLWithPath: singlePath)

num += 1

musicModel.musicNum=num;

musicArryList.append(musicModel)

}

musicArry=musicArryList

return musicArry!

}else{

return musicArry!

}

}

一个音乐播放器每次播放都只能放一首歌,于是我将其封装成了一个AudioPlayer单例类,其实也不能算单例,应该叫工具类比较合适。

import UIKit

import AVFoundation

final class AudioPlayer: NSObject {

private static var instance: AVAudioPlayer? = nil //static 直到被销毁 全局存在

private static var activeMusic:Music?=nil

private static var isRandomPlay=false

static func share(model:Music) -> Bool {

do{

try instance = AVAudioPlayer(contentsOf: model.musicURL!)

}

catch{

instance=nil;

print("error")

return false;

}

instance?.play()

activeMusic=model

return true

}

//停止

static func stop(){

instance?.stop()

}

//播放

static func play()->Bool{

if (instance?.isPlaying)! {

instance?.pause()

return false

}else{

instance?.play()

return true

}

}

//暂停

static func pause(){

instance?.pause()

}

//下一曲

static func nextsong( num:Int)->Bool{

var num = num

var musicArry:Array<Music>!

musicArry=Music.getALL()

if isRandomPlay{

num = Int(arc4random_uniform(UInt32(musicArry.count-1)))

}

if(share(model: musicArry[num])){

return true

}else{

return false

}

}

//上一曲

static func prevsong(num:Int)->Bool{

var num = num

var musicArry:Array<Music>!

musicArry=Music.getALL()

if isRandomPlay{

num = Int(arc4random_uniform(UInt32(musicArry.count-1)))

}

if(share(model: musicArry[num])){

return true

}else{

return false

}

}

//声音控制

static func voice(num:Float){

instance?.volume=num

}

//进度条相关

static func progress()->Double{

return (instance?.currentTime)!/(instance?.duration)!

}

static func musicDuration()->Double{

return (instance?.duration)!

}

static func currentTime()->Double{

return (instance?.currentTime)!

}

//当前播放的音乐

static func activeSong()->Music?{

return activeMusic

}

//是否在播放音乐

static func isPlaying()->Bool{

return (instance?.isPlaying)!

}

//随机播放

static func musicRandomPlay()->Bool{

if  isRandomPlay==false{

isRandomPlay=true

return isRandomPlay

}else{

isRandomPlay=false

return isRandomPlay

}

}

}

3.音乐播放

所有歌曲及其信息都能拿到了,展示在tableView上我就不用多说,播放音乐也只需要在tableView的相应点击方法里使用AudioPlayer类的share方法将对应的歌曲model传入即可,这里有个如何让miniplayer展示所点击歌曲的问题,我是将tableView放进ContainerView,tableView相当于主视图的子视图,而miniplayer是在主视图里,这里就要用到子视图向父视图回传值的方法,在这里我是采用的闭包回传,其实也不需要传什么值,只需要让主视图知道子视图被点击了即可,因为我可以通过AudioPlayer类来得到当前播放的歌曲信息。swift里的闭包传值在语法上和oc的区别也是很大,花了我不少时间- -

子视图里:

var musicPlayByTableViewCell: ((Int) -> Void)//声明

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

musicPlayByTableViewCell?(indexPath.row)

tableView.deselectRow(at: indexPath, animated: true)//取消被选中状态

}

主视图里:

self.musicTalbleVC.musicPlayByTableViewCell={

[weak self]  musicNum in self?.musicModel=self?.musicArry[musicNum]

self?.nowNum=musicNum

self?.miniPlayerWork()

}

3.1界面功能及相关细节

音乐播放时的界面也就是几个button和常见的视图控件,说说进度条,AVAudioPlayer类提供了当前进度,以及总时长,所以我是用定时器每一秒获取一次当前进度的方法,再当前进度除以总进度使用即可,上下曲因为我在获取所有歌曲时就将每首歌曲编了号,上下曲就只需要将编号加一或减一就可以了,包括随机播放也只需要使用随机函数随机总歌曲编号就行了,还有些界面上的细节,在详细歌曲播放界面点击了暂停,回到主视图时miniplayer的图标及相关信息也应该与其同步哦。tableView列表上也将当前播放的歌曲进行了高亮展示(加了歌活跃标记),在这里,我在musicmodel里添加了IsActive属性,并在tableView的Cell里进行了判断,如果cell展示的歌曲是当前正在播放的歌曲isActive为true展示活跃标记。还有音乐播放完毕后需要自动播放下一曲哦,这里我是用的定时器控件,读取歌曲进度进度完了就播放下一曲(相当点击了一次下一曲按钮)

3.12tabBar控制界面

在storyBoard上是直接拖的TabBar,和直接用tabBarController大不一样,点击不同的图标响应不同的事件ContainerView里的视图控制器也就相应的变化,关于如何改变ContainerView里的视图控制器我也是找了好久,还比较复杂,但确实ContainerView很好用啊!

ContainerView:更改视图控制器

func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {

if item.tag == 1 {

let newController = self.musicTalbleVC!

let oldController = childViewControllers.last!

if newController != oldController {

//  self.setStatusBarBackgroundColor(color: UIColor.white)

oldController.willMove(toParentViewController: nil)

addChildViewController(newController)

newController.view.frame = oldController.view.frame

//isAnimating = true

transition(from: oldController, to: newController, duration: 0.5, options: UIViewAnimationOptions.transitionFlipFromLeft, animations: nil, completion: { (finished) -> Void in

oldController.removeFromParentViewController()

newController.didMove(toParentViewController: self)                //self.isAnimating = false

})

}

}else{

let newController = self.moreVC!

let oldController = childViewControllers.last!

if newController != oldController {

self.setStatusBarBackgroundColor(color: UIColor.clear)

oldController.willMove(toParentViewController: nil)

addChildViewController(newController)

newController.view.frame = oldController.view.frame

transition(from: oldController, to: newController, duration: 0.5, options: UIViewAnimationOptions.transitionFlipFromRight, animations: nil, completion: { (finished) -> Void in

oldController.removeFromParentViewController()

newController.didMove(toParentViewController: self)                //self.isAnimating = false

})

}

}

}

3.13音乐的后台播放以及锁屏和上拉栏展示音乐信息

音乐的后台播放,因为我还从为接触过应用后台运行这一块,所以我也只是参照网上的代码将功能做出来了而已,还有不完善的地方,后台播放中断(如打电话)后不会恢复播放。上拉栏展示音乐信息以及之中的按钮触发方法,都是系统封装好了的 直接用就是了。

话说很多警告呀!

func setBackground() {

//大标题 - 小标题  - 歌曲总时长 - 歌曲当前播放时长 - 封面

self.musicModel=AudioPlayer.activeSong()

var settings = [MPMediaItemPropertyTitle: self.musicModel?.musicName,

MPMediaItemPropertyArtist: self.musicModel?.musicAuthor ,

MPMediaItemPropertyPlaybackDuration: "\(AudioPlayer.musicDuration())",

MPNowPlayingInfoPropertyElapsedPlaybackTime: "\(AudioPlayer.currentTime())",MPMediaItemPropertyArtwork: MPMediaItemArtwork.init(image: UIImage (data: (self.musicModel?.musicimg)!)!)] as [String : Any]

MPNowPlayingInfoCenter.default().setValue(settings, forKey: "nowPlayingInfo")

if AudioPlayer.progress() > 0.99 { // 自动播放下一曲 ()后台

self.nowNum=self.nowNum+1

if self.nowNum>=self.musicArry.count{

self.nowNum=0

}

if AudioPlayer.nextsong(num: self.nowNum){

refreashView()

}

}

}

4.最后

这是刚入行的菜鸡的第一篇博客,肯定有很多不妥当的地方,希望大家见谅,项目也没做多久,对swift的理解还很浅,肯定不如大大们的法眼,我也只希望通过写这篇博客,总结一下我学到的知识,分享出来,大家互相交流学习。

附源码 https://github.com/calvinWen/SwiftMusicPlayer

Swift 3 :基于 AVAudioPlayer 的简单音乐播放器相关推荐

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

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

  2. 基于JAVAvue开发一个简单音乐播放器计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVAvue开发一个简单音乐播放器计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVAvue开发一个简单音乐播放器计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目 ...

  3. 基于QT的网络音乐播放器(一)

    自学Qt已经有一段时间了,但是始终感觉自己还是很弱(其实并不是感觉自己很弱,是自己本来就很弱,哈哈).自己也照着书上敲了几个例子,但觉得还是要写点东西才能真正运用起来.所以,前段时间就写了个很简单的音 ...

  4. 在HarmonyOS中实现基于JS卡片的音乐播放器

    /   今日科技快讯   / 近日,苹果首席执行官蒂姆·库克接受<时代>杂志专访,谈及他本人对领导力.企业价值和新技术的看法.库克表示,苹果不仅要引领创新,还要努力让世界变得更安全更公平, ...

  5. [内附完整源码和文档] 基于Android的手机音乐播放器的设计与实现

    摘 要 随着Android系统和移动互联网的快速崛起,手机已经成为人们生活不可缺的一部分,在现代人的生活中,人们生活节奏的加快,生活压力越来越大,碎片化的时间越来越多,那么一个可以在碎片化的时间内调节 ...

  6. 【网络收录】基于51单片机开发音乐播放器

    [网络收录]基于51单片机开发音乐播放器 本文作者:天析 作者邮箱:2200475850@qq.com 发布时间: Thu, 22 May 2014 18:14:00 +0800 特别声明:本资料来源 ...

  7. (附源码)springboot+基于微信小程序音乐播放器的设计与实现 毕业设计271156

    Springboot音乐播放小程序的设计与实现 摘 要 本文设计了一种基于微信小程序的音乐播放器,系统为人们提供了方便快捷.即用即搜的音乐搜索播放服务,包括音乐资讯.音乐库推荐.交流论坛.注册登录.最 ...

  8. java计算机毕业设计vue开发一个简单音乐播放器源码+mysql数据库+系统+lw文档+部署

    java计算机毕业设计vue开发一个简单音乐播放器源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计vue开发一个简单音乐播放器源码+mysql数据库+系统+lw文档+部署 本源码技 ...

  9. 张利国,龚海平,王植萌.android移动开发入门与进阶,开题报告-基于Android的手机音乐播放器的设计与实现.doc...

    盐城师范学院 毕业设计开题报告 题 目: 基于android的手机音乐播放器 的设计与实现 姓 名: 二级学院: 信息工程学院 专 业: 软件工程 班 级: 12(1) 学 号: 指导教师: 职称: ...

最新文章

  1. Eclipse 代码自动提示的设置
  2. 人们把通信技术计算机技术控制技术合称为,湖北汽车工业学院大学计算机基础复习题(费劲整理,带答案,考试命中概率很大).docx...
  3. 经典C语言程序100例之十四
  4. 读书随笔:The Book of Why——CHAPTER 3:From Evidence to Causes: Reverend Bayes Meets Mr. Holmes
  5. Git教程——分支 (branch)
  6. mybatis 多数据源_Spring Boot 整合Mybatis实现多数据源配置及踩过的坑
  7. 荣耀智慧屏 55英寸屏幕 搭载鸿蒙OS,3799元起!荣耀智慧屏发布:55英寸4K全面屏+首发鸿蒙OS+无广告...
  8. 基本知识 100024
  9. 2020年7月19日训练总结
  10. 数学分析对计算机有帮助吗,计算机辅助数学分析教学的好处
  11. jarvis oj typo
  12. brew install/update过程中download failed的问题及解决方法 2016年01月21日 10:29:23 strawman_dxj 阅读数:6013 标签: brew in
  13. Windows7 开机自启脚本
  14. 基于Binlog、FlinkCDC、Doris实现实时数据同步
  15. 最新版Ubuntu 18.04将语言改为中文(简体)
  16. 木马也办“假身份证” 数字签名面临信任危机
  17. 您可以在哪里播放最喜欢的圣诞节特价商品
  18. #边学边记 必修4 高项:对事的管理 第5章 项目成本管理 之 制订成本管理计划
  19. 体验世界上五十大开心事
  20. 微信小程序动态设置tab-bar

热门文章

  1. 在c语言中void是什么,C语言中void是什么意义?_后端开发
  2. WIN7上的“雅黑字体” WIN8上的“雅黑字体”
  3. linux6.8 增大 dev shm,增加/dev/shm大小
  4. 20221207英语学习
  5. Office 2003安装时自动输入序列号
  6. office和操作系统正版序列号
  7. 12306 js刷票脚本
  8. 计算机网络工程机应用常用技术,计算机网络工程实用技术资源 4.ppt
  9. 7个步骤轻松创建你的专属社交媒体二维码!
  10. 蓝桥杯之单片机设计与开发——第八届省赛_基于单片机的电子钟程序设计与调试