/** 歌曲名称 */
    var name: String?
    /** 歌曲文件名称 */
    var filename: String?
    /** 歌曲文件名称 */
    var lrcname: String?
    /** 演唱者 */
    var singer: String?
    /** 歌手头像 */
    var singerIcon: String?
    /** 专辑图片 */
    var icon: String?//重写了下面的方法,此方法是必须重写的
 override init() {
        super.init()
    }
    /** KVC */
    init(dict : [String : AnyObject]) {
        super.init()
        setValuesForKeysWithDictionary(dict)
    }//异常处理
    override func setValue(value: AnyObject?, forUndefinedKey key: String) {
    }class XFJQQMusicDataTool: NSObject {
    //** 设计一个方法,用来返回数据模型 */
    class func getMusicList( result: (musicMs : [XFJQQMusicModel]) ->()) {
        //加载本地的plist文件
        guard let path = NSBundle.mainBundle().pathForResource("Musics.plist", ofType: nil) else {
            result(musicMs: [XFJQQMusicModel]())
            return
        }
        //加载文件的内容
        guard let dictArray = NSArray(contentsOfFile: path) else {
            result(musicMs: [XFJQQMusicModel]())
            return
        }
        //把字典转成模型
        var resultMs = [XFJQQMusicModel]()
        //遍历
        for dict in dictArray {
            let musicM = XFJQQMusicModel(dict: dict as! [String : AnyObject])
            resultMs.append(musicM)
        }
        //以闭包的形式返回出去
        result(musicMs: resultMs)
    }
}extension XFJQQListTVC {
    //初始化设置
    func setUpInit() {
        setUpTableView()
        setUpNavigationBar()
    }
    //通过一个方法来设置tableView的相关设置
    private  func setUpTableView() {
        //tableView的背景图片
        let backView = UIImageView(image: UIImage(named: "QQListBack"))
        tableView.backgroundView = backView
        //cell的高度
        tableView.rowHeight = 60
        //分割线
        tableView.separatorStyle = .None
    }
    //设置导航条隐藏
    private  func setUpNavigationBar() {
        navigationController?.navigationBarHidden = true
    }
    //设置状态栏的样式
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }
}override func viewDidLoad() {
        super.viewDidLoad()
        XFJQQMusicDataTool.getMusicList { (musicMs) -> () in
            //将返回的数组装入模型中
            self.musicMs = musicMs
        }        
        setUpInit()
    }//只要有数据变化,就刷新表格
    var musicMs : [XFJQQMusicModel] = [XFJQQMusicModel]() {
        didSet {
            tableView.reloadData()
        }
    }    //** 歌手的头像  */
    @IBOutlet weak var iconImageView: UIImageView!
    //** 歌名 */
    @IBOutlet weak var songName: UILabel!
    //** 演唱者 */
    @IBOutlet weak var singerName: UILabel!    //重写模型的set方法,用模型给xib的属性赋值
    var musicM : XFJQQMusicModel? {
        didSet {
            //容错处理
            if musicM?.icon != nil {
                iconImageView.image = UIImage(named:musicM!.icon!)
            }
            songName.text = musicM?.name
            singerName.text = musicM?.singer
        }
    }    //当加载xib的时候一定会调用
    override func awakeFromNib() {
        super.awakeFromNib()
        //处理头像
        iconImageView.layer.cornerRadius = iconImageView.width * 0.5
        iconImageView.layer.masksToBounds = true
    }    //提供一个方法,返回由xib创建的cell
    class  func cellWithTableView(tableView : UITableView) ->XFJQQMusicListCell {
        let cellID = "cellID"
        var cell = tableView.dequeueReusableCellWithIdentifier(cellID) as? XFJQQMusicListCell
        if cell == nil {
            //检查是否有循环利用
            print("创建cell")
            cell = NSBundle.mainBundle().loadNibNamed("XFJQQMusicListCell", owner: nil, options: nil).first as? XFJQQMusicListCell
        }
        return cell!
    }    //重写cell的hightlight方法,一遍点击cell的时候cell不在高亮
    override func setHighlighted(highlighted: Bool, animated: Bool) {
    }//动画的样式
enum AnimationType {
    case Rotation
    case Translation
}///MARK : - 动画(核心动画)
extension XFJQQMusicListCell {
    func beginAnimation(type : AnimationType) {
        //用switch做判断(执行哪种动画)
        switch type {
        case .Rotation:
            //移除上一个动画
            self.layer.removeAnimationForKey("rotation")
            //做怎样的动画
            let animation = CAKeyframeAnimation(keyPath: "transform.rotation.z")
            //动画之间的角度
            animation.values = [M_PI * 0.25, 0]
            //动画时长
            animation.duration = 0.2
            //添加动画
            self.layer.addAnimation(animation, forKey: "rotation")
        case .Translation:
            self.layer.removeAnimationForKey("translation")
            let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
            animation.values = [60, 0]
            animation.duration = 0.3
            self.layer.addAnimation(animation, forKey: "translation")
        }
    }
}    //** 行 */
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return musicMs.count
    }    //** cell显示的内容 */
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        //通过方法获得cell
        let cell = XFJQQMusicListCell.cellWithTableView(tableView)
        //取出模型
        let musicM = musicMs[indexPath.row]
        //赋值(cell.musicM: 模型的set方法,通过该方法来赋值)
        cell.musicM = musicM
        //返回cell
        return cell
    }    //开始做动画
    override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
        //将系统的cell转为xib的cell
        let cell = cell as! XFJQQMusicListCell
        //开始动画
        cell.beginAnimation(AnimationType.Translation)
    }class XFJQQMusicTool: NSObject {
    //创建播放器
    var avplayer : AVAudioPlayer?
    //设置一个方法,又外界直接传入一个文件名,然后就直接播放
    func getplayMusic(name : String) ->(){
        //获取传入的文件url(并且判断)
        guard  let url = NSBundle.mainBundle().URLForResource(name, withExtension: nil) else {return}
        //由url来判断播放的是否是同一首歌
        if url == avplayer?.url {
            //播放的是同一首歌
            avplayer?.play()
            return
        }
        //播放传入的url的歌曲
        do {
            avplayer = try AVAudioPlayer(contentsOfURL: url)
        }catch{
            //打印错误信息
            print(error)
            return
        }
        //准备播放
        avplayer?.prepareToPlay()
        //开始播放
        avplayer?.play()
    }    //** 重新播放 */
    func resumeCurrentMusic() ->() {
        avplayer?.play()
    }
    //** 暂停播放 */
    func pauseCurrentMusic() ->() {
        avplayer?.pause()
    }    //设置单例
    static let shareInstance = XFJQQMusicOperationTool()//设置一个属性记录正在播放的音乐的角标(并且提供set方法)
    var index = 0 {
        didSet {
            if index < 0
            {
                index = (musicList?.count ?? 0) - 1
            }
            if index > (musicList?.count ?? 0) - 1
            {
                index = 0
            }
        }
    }    //** 上一首 */
    func preMusic() ->() {
        index -= 1
        //判断
        if let tempList = musicList {
            //取出模型
            let musicM = tempList[index]
            //根据模型播放音乐
            getplayMusic(musicM)
        }
    }    //** 下一首 */
    func nextMusic() ->() {
        index += 1
        //判断
        if let tempList = musicList {
            //取出模型
            let musicM = tempList[index]
            //根据模型播放音乐
            getplayMusic(musicM)
        }
    }    //创建模型的音乐播放列表
    var musicList : [XFJQQMusicModel]?
    //创建操作音乐的对象
    let tool = XFJQQMusicTool()
        //提供一个方法由外界通过这个方法播放音乐
    func getplayMusic(musicM : XFJQQMusicModel) ->() {
        //通过传入的模型,拿到模型中歌名属性(filename)
        let fileName = musicM.filename ?? ""
        //完成对歌曲的播放
        tool.getplayMusic(fileName)
        //容错处理(如果没有歌曲,就直接退出)
        if musicList == nil {
            return
        }
        //记录下当前在播放的音乐的索引
        index = (musicList?.indexOf(musicM))!
    }    //** 播放 */
    func playCurrentMusic() ->() {
        tool.resumeCurrentMusic()
    }
    //** 暂停 */
    func pauseCurrentMusic() ->() {
        tool.pauseCurrentMusic()
    }    //用户点击了某行cell,播放对应的歌曲
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        //取出行模型
        let musicM = musicMs[indexPath.row]
        //播放
        XFJQQMusicOperationTool.shareInstance.getplayMusic(musicM)
        //通过绑定的suge,当点击某行cell的时候,跳转到下一个界面
        performSegueWithIdentifier("listToDetail", sender: nil)
    }///MARK : - 只负责属性
class XFJQQDetailVC: UIViewController {
    //** 歌手头像 */
    @IBOutlet weak var foreImageView: UIImageView!
    //** 歌词能显示的并且滚动的View */
    @IBOutlet weak var lrcBackView: UIScrollView!
    //** 进度 */
    @IBOutlet weak var progressSlider: UISlider!
    //** 歌名 */
    @IBOutlet weak var lrcLabel: UILabel!
    //** 展示歌词的view */
    var lrcview : UIView?
}    //** 下一首音乐 */
    @IBAction func nextButton()
    {
        XFJQQMusicOperationTool.shareInstance.nextMusic()
    }
    //** 上一首音乐 */
    @IBAction func previous()
    {
        XFJQQMusicOperationTool.shareInstance.preMusic()
    }
    //** 播放和暂停 */
    @IBAction func playAndPause(button : UIButton)
    {
        button.selected = !button.selected
        //判断
        if button.selected {
            XFJQQMusicOperationTool.shareInstance.pauseCurrentMusic()
        }else {
            XFJQQMusicOperationTool.shareInstance.playCurrentMusic()
        }
    }    //** 设置方法用来添加调用一次性的设置 */
    private func setUpOnce() ->() {
        addLrcView()
        setProgressSlider()
    }
    //** 设置方法用来添加调用多次的设置 */
    private func setUpLrcFrame() ->() {
        setUpLrcViewFrame()
        setUpForeImage()
    }    //** 设置进度条的背景图片 */
    private func setProgressSlider() ->() {
        progressSlider.setThumbImage(UIImage(named: "player_slider_playback_thumb"), forState: UIControlState.Normal)
    }    //** 计算显示歌词的view的frame */
    private func setUpLrcViewFrame() {
        //lrcview的frame值
        lrcview?.frame = lrcBackView.bounds
        //lrcview的x值
        lrcview?.x = lrcBackView.width
        //设置拖动显示歌词的view的contensize
        lrcBackView.contentSize = CGSizeMake(lrcBackView.width * 2.0, 0)
    }    //** 负责添加控件(只需要添加一次即可) */
    private func addLrcView() ->() {
        //创建显示歌词的view
        lrcview = UIView()
        //设置背景颜色
        lrcview?.backgroundColor = UIColor.redColor()
        //添加到滚动的view中
        lrcBackView.addSubview(lrcview!)
        //开启分页模式
        lrcBackView.pagingEnabled = true
        //隐藏水平滚动条
        lrcBackView.showsHorizontalScrollIndicator = false
        //设置scorllView的代理
        lrcBackView.delegate = self
    }    //** 设置圆角图片 */
    private func setUpForeImage() ->() {
        foreImageView.layer.cornerRadius = foreImageView.width * 0.5
        foreImageView.layer.masksToBounds = true
    }
    //设置状态栏的样式
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }    //这些方法只需要调用一次即可
    override func viewDidLoad() {
        super.viewDidLoad()
        setUpOnce()
    }
    // 在视图加载好之后, 有可能, 里面拿到的不是真实的最终frame, 有可能是xib里面的大小
    //该方法会频繁调用,但是调用越频繁,frame越准确
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        setUpLrcFrame()
    }///MARK : - scrollView的代理方法的实现
extension XFJQQDetailVC : UIScrollViewDelegate {
    func scrollViewDidScroll(scrollView: UIScrollView) {
        let alpha = 1 - scrollView.contentOffset.x / scrollView.width
        //设置背景图片的透明度
        foreImageView.alpha = alpha
        //设置显示歌名的label透明度
        lrcLabel.alpha = alpha
    }
}原文:http://blog.csdn.net/xf931456371/article/details/51440805