swift版QQ音乐播放器(一)

一 部分功能图(后面会完善)

二 讲解思路

1 项目目录结构搭建

2 抽取工具类

3 自定义cell

4 分层思想

5 业务逻辑

三 项目目录搭建和相关配置

1 采用搭建搭建结构思路 : MCV模式

—-> 1.1 文件夹图片 :

2 注意 一 : 当我们在创建目录的时候,直接将info.plist文件拖入到System的时候,编译的时候,会报错.原因是找不到info.plist文件.

—-> 2.1 处理方式 : 直接找到工程文件,然后找到General,里面会有一个现实info的按钮,点击即可解决.

3 注意二 : 修改好了注意一的点,然后编译的时候会出现警告,警告提示info.plist文件已经加载过了,这是找到对应的info.plist文件,按照下面配置就可解决.

4 设置应用图标和应用启动图片我这里就不再讲了,前面博客中都有说明

5 分析采用纯代码搭建还是采用storyboard搭建项目结构?

—-> 5.1 通过app的部分效果图可以知道,采用storyboard是最简单的选择(UINavigationController;UITableViewController;UIViewController)

6 由于需要点击某行的cell然后跳转页面,这里我们直接绑定一个segue

四 创建模型

1 设置展示在tableView中数据的模型

2 根据提供数据的plist文件,设置需要写在模型中的属性

—-> 2.1 经验 : 按照下面的方式操作可以提高开发效率(一些开发细节)
—-> 2.2 图一 :通过下面的方式打开plist文件

—-> 2.3 图二 : 赋值打开后的plist文件中一对字典数据

—-> 2.4 直接在模型的文件中通过替换的方式直接对2.3的数据操作,可以很快的设置需要的属性.

3 模型属性代码

    /** 歌曲名称 */
    var name: String?
    /** 歌曲文件名称 */
    var filename: String?
    /** 歌曲文件名称 */
    var lrcname: String?
    /** 演唱者 */
    var singer: String?
    /** 歌手头像 */
    var singerIcon: String?
    /** 专辑图片 */
    var icon: String?

4 用KVC的方式来实现转模型

//重写了下面的方法,此方法是必须重写的
 override init() {
        super.init()
    }

    /** KVC */
    init(dict : [String : AnyObject]) {
        super.init()
        setValuesForKeysWithDictionary(dict)
    }

5 容错处理

—-> 5.1 原因 : 如果不重写下面的代码,当字典中的key和value有对不上号的情况下,会直接报错,所以这里我们做出容错处理.
//异常处理
    override func setValue(value: AnyObject?, forUndefinedKey key: String) {
    }

五 封装工具类

1 封装原因 : 提供接口,代码复用

2 返回模式 : 采用闭包回调的方式将数据回调出去

3 最终目的 : 此方法的设计,只需要在外界调用的时候,负责提供音乐中的数据,具体怎么提供,就是工具类中的问题了.

4 采用闭包回调的好处 : 如果以后想讲请求的方式更换为网络请求,那么如果采用闭包回调的方式就不需要修改接口,直接将接口内部的实现修改成网络请求就可以达到目的.(这里是直接加载本地的数据)

5 工具类文件夹

6 代码部分 :

—-> 6.1 判断
—-> 6.2 遍历
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)
    }
}

六 UITableViewController的相关设置

1 展示数据的tableView文件(注意和storyboard中的控制器绑定)

2 设置tableView的背景图片

3 设置状态栏的样式

4 设置导航条隐藏

5 上面都是对tableView的处理方式,我们直接采用类扩展,然后将三个方法放在一个供外界提供的方法中,让外界通过直接调用一个方法,就能对三个要求的设置

6 代码 :

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
    }
}

7 在viewDidLoad中直接调用setUpInit()方法和对工具类提供的方法调用

override func viewDidLoad() {
        super.viewDidLoad()
        XFJQQMusicDataTool.getMusicList { (musicMs) -> () in
            //将返回的数组装入模型中
            self.musicMs = musicMs
        }
        setUpInit()
    }

8 在展示内容的tableView中提供一个展示数据的模型的set方法

—-> 8.1 目的 : 当数据只要发生改变,就刷新tableView
//只要有数据变化,就刷新表格
    var musicMs : [XFJQQMusicModel] = [XFJQQMusicModel]() {
        didSet {
            tableView.reloadData()
        }
    }

七 自定义cell

1 自定义原因 : 系统的cell无法满足需求

2 采用方式 : xib(由于每行cell内容的样式都一样)

3 创建继承与UITableViewCell的文件,同时创建xib

4 xib的相关设置

—-> 4.1 我这里只说明绑定cell的ID,以便重复利用(其它的不说了)

5 通过拖线的方式,拿到xib中的属性

    //** 歌手的头像  */
    @IBOutlet weak var iconImageView: UIImageView!
    //** 歌名 */
    @IBOutlet weak var songName: UILabel!
    //** 演唱者 */
    @IBOutlet weak var singerName: UILabel!

6 重写模型的set方法,以便外界通过set方法来赋值(这里我直接给上代码,没什么好说明的,注意容错处理就行)

    //重写模型的set方法,用模型给xib的属性赋值
    var musicM : XFJQQMusicModel? {
        didSet {
            //容错处理
            if musicM?.icon != nil {
                iconImageView.image = UIImage(named:musicM!.icon!)
            }
            songName.text = musicM?.name
            singerName.text = musicM?.singer
        }
    }

7 有app的效果图我们需要对明星的头像处理

    //当加载xib的时候一定会调用
    override func awakeFromNib() {
        super.awakeFromNib()
        //处理头像
        iconImageView.layer.cornerRadius = iconImageView.width * 0.5
        iconImageView.layer.masksToBounds = true
    }

8 在cell的内部提供一个方法,让外界直接调用就可以拿到cell,不需要将该方法写在创建cell的数据源方法中,只要负责提供一个接口就行,至于怎么实现的,就交给cell内部,外界不需要管(自定义cell的核心部分,需要大家学习学习,并且掌握).

    //提供一个方法,返回由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!
    }

9 取消点击cell的高亮状态(也是属于cell的,直接写在cell的内部就可以)

    //重写cell的hightlight方法,一遍点击cell的时候cell不在高亮
    override func setHighlighted(highlighted: Bool, animated: Bool) {

    }

10 cell的动画效果(核心动画)

—-> 10.1 该部分也是属于cell内部的事情,直接将代码写在自定义cell内部就可以
—-> 10.2 怎么样构建接口?通过由外界传入的枚举值,用switch来作为判断以哪种模式来执行cell的动画
—-> 10.3 在cell的内部定义枚举值
//动画的样式
enum AnimationType {
    case Rotation
    case Translation
}
—-> 10.4 cell的动画
///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")
        }
    }
}

11 数据源方法

—-> 11.1 tableView的行数(由模型的个数决定)
    //** 行 */
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return musicMs.count
    }
—-> 11.2 每个cell显示的内容(获取自定义cell,内容有模型决定)
    //** 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
    }
—-> 11.3 开始做动画(调用cell中动画的API,注意将cell的类型转为自定义的类型)
    //开始做动画
    override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
        //将系统的cell转为xib的cell
        let cell = cell as! XFJQQMusicListCell
        //开始动画
        cell.beginAnimation(AnimationType.Translation)
    }

八 封装对音乐操作的工具类(分三层调用的思想)–>第一层

1 封装工具类的原因 : 对外界提供一个接口,在内部只负责对音乐的播放,暂停,快进和快退等功能.外面不需要关心内部怎么实现的,值负责调用接口就可以

2 创建工具类文件

3 播放音乐文件

—-> 3.1 设置接口 : 需要让外界传入一个音乐文件名,然后在方法内做出一系列的判断,才开始播放音乐文件
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()
    }

4 提供两个接口作为控制播放器中间按钮控制暂停和重新播放的状态(内部直接控制,外界只需要调用接口)

    //** 重新播放 */
    func resumeCurrentMusic() ->() {
        avplayer?.play()
    }
    //** 暂停播放 */
    func pauseCurrentMusic() ->() {
        avplayer?.pause()
    }

九 音乐的业务逻辑工具类的封装(分层思想第二层)

1 封装原因 : 通过该曾来调用最内部的第一层来实现相应的业务逻辑

2 封装第二层工具类的文件

3 设置单例 : 保证每次创建的都是同一个对象

    //设置单例
    static let shareInstance = XFJQQMusicOperationTool()

4 用设置属性记录当前播放音乐的角标的方式来实现点击上一首和下一首音乐的播放(提供一个set方法)

//设置一个属性记录正在播放的音乐的角标(并且提供set方法)
    var index = 0 {
        didSet {
            if index < 0
            {
                index = (musicList?.count ?? 0) - 1
            }
            if index > (musicList?.count ?? 0) - 1
            {
                index = 0
            }
        }
    }

5 上一首歌曲(内部直接调用播放音乐的方法)–>因为每次点击上一首歌曲的时候,都是从头开始播放的

    //** 上一首 */
    func preMusic() ->() {
        index -= 1
        //判断
        if let tempList = musicList {
            //取出模型
            let musicM = tempList[index]
            //根据模型播放音乐
            getplayMusic(musicM)
        }
    }

6 下一首歌曲播放(内部直接调用播放音乐的方法)–> 因为每次点击下一首歌曲的时候,都是从头开始播放的

    //** 下一首 */
    func nextMusic() ->() {
        index += 1
        //判断
        if let tempList = musicList {
            //取出模型
            let musicM = tempList[index]
            //根据模型播放音乐
            getplayMusic(musicM)
        }
    }

7 播放音乐(直接在该类中创建一个方法来调用第一层中播放音乐的方法.注意需要闯入音乐的文件名)

    //创建模型的音乐播放列表
    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))!
    }

8 播放和暂停(通过调用第一层中的方法来实现)

    //** 播放 */
    func playCurrentMusic() ->() {
        tool.resumeCurrentMusic()
    }

    //** 暂停 */
    func pauseCurrentMusic() ->() {
        tool.pauseCurrentMusic()
    }

9 在点击cell的数据源方法中,直接调用第二层中的接口,就能达到播放音乐的目的(第三层调用)

    //用户点击了某行cell,播放对应的歌曲
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        //取出行模型
        let musicM = musicMs[indexPath.row]
        //播放
        XFJQQMusicOperationTool.shareInstance.getplayMusic(musicM)

        //通过绑定的suge,当点击某行cell的时候,跳转到下一个界面
        performSegueWithIdentifier("listToDetail", sender: nil)
    }

十 展示歌词

1 分析 : 通过app的功能可以看出来,拖动显示歌词的view可以往左滑动,那么显示歌词的view可以暂时用普通的view来做,装view的父控件就是UIScrollerView,因为需要滚动的.

2 创建显示暂停,开始,上一首和下一首的类(详情页)

3 布局详情页(这里就不细说了,但是要注意毛玻璃的设置可以通过代码,也可以通过直接在storyboard中拖一个UIToolBar控件来设置)

4 通过从storyboard中的拖线拿到相应的控件

—-> 4.1 下面这个类只负责属性(这样分层也是一种方便管理的思想)
///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?
}

5 拖过拖线处理暂停,开始,上一首和下一首的业务逻辑

—-> 5.1 扩充一个类扩展,将方法写在里面(注意里面的方法是通过拿到单例来调用的)
    //** 下一首音乐 */
    @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()
        }
    }

6 在上面的类扩展中我们通过设置两个方法来调用下面部分的代码

    //** 设置方法用来添加调用一次性的设置 */
    private func setUpOnce() ->() {
        addLrcView()
        setProgressSlider()
    }

    //** 设置方法用来添加调用多次的设置 */
    private func setUpLrcFrame() ->() {
        setUpLrcViewFrame()
        setUpForeImage()
    }

7 设置进度条的背景图片(只需要设置一次)

    //** 设置进度条的背景图片 */
    private func setProgressSlider() ->() {
        progressSlider.setThumbImage(UIImage(named: "player_slider_playback_thumb"), forState: UIControlState.Normal)
    }

8 计算显示歌词的view的frame(执行多次)

    //** 计算显示歌词的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)
    }

9 负责添加显示歌词的控件view(只需要添加一次即可)

    //** 负责添加控件(只需要添加一次即可) */
    private func addLrcView() ->() {
        //创建显示歌词的view
        lrcview = UIView()
        //设置背景颜色
        lrcview?.backgroundColor = UIColor.redColor()
        //添加到滚动的view中
        lrcBackView.addSubview(lrcview!)
        //开启分页模式
        lrcBackView.pagingEnabled = true
        //隐藏水平滚动条
        lrcBackView.showsHorizontalScrollIndicator = false
        //设置scorllView的代理
        lrcBackView.delegate = self
    }

10 设置图片的圆角和状态栏的样式

    //** 设置圆角图片 */
    private func setUpForeImage() ->() {
        foreImageView.layer.cornerRadius = foreImageView.width * 0.5
        foreImageView.layer.masksToBounds = true
    }

    //设置状态栏的样式
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }

11 在第6点中我们直接通过两个方法来调用同时也达到了分层的调用

    //这些方法只需要调用一次即可
    override func viewDidLoad() {
        super.viewDidLoad()
        setUpOnce()
    }
    // 在视图加载好之后, 有可能, 里面拿到的不是真实的最终frame, 有可能是xib里面的大小
    //该方法会频繁调用,但是调用越频繁,frame越准确
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        setUpLrcFrame()
    }

12 当拖动显示歌词的view的时候,背景图片慢慢的呈现透明样式,可直接通过下面代理方法解决

///MARK : - scrollView的代理方法的实现
extension XFJQQDetailVC : UIScrollViewDelegate {
    func scrollViewDidScroll(scrollView: UIScrollView) {
        let alpha = 1 - scrollView.contentOffset.x / scrollView.width
        //设置背景图片的透明度
        foreImageView.alpha = alpha
        //设置显示歌名的label透明度
        lrcLabel.alpha = alpha
    }
}

十一 总结

1 可能出现错误的地方 : 在处理详情页中间的图片圆角可能会出现图片不是很圆的情况?

2 直接在viewWillLayoutSubviews中设置才是最准确的(解决).

3 掌握工具类的分层思想对初学者来说可能有点不能接受,但是能明白将是一种非常实用的思想(理解).

4 注意自定义cell中,在自定义cell的内部提供一个放发,直接返回cell,不需要将cell的实现写在数据源方法中,只需要在数据源方法中调用接口,就能达到目的(掌握).

5 最后,希望大家尽可能的去理解吧,不懂的可以随时给我留言.如果大家觉得我写的博客还满意的话,麻烦大家关注我的官方博客,谢谢!!!!

时间: 2024-10-05 07:04:35

swift版QQ音乐播放器(一)的相关文章

swift版QQ音乐播放器(二)

一 完善部分的QQ音乐效果图 二 需要完善点 1 歌曲的切换和暂停播放 2 歌曲当前播放时间和歌曲总时间的更新 3 进度条的处理 4 歌手头像处理 5 头像动画效果 6 歌词的进度显示 8 完善细节 三 添加歌曲展示页面中的动画效果 1 代码书写位置 : 由于展示歌词的控制器的UITableViewController,那么我们可以使用代理方法.当用户拖动tableView的时候,会调用一个方法,在该方法中实现动画效果 2 思路 : 通过拿到第一个cell和最后一个cell来计算中间cell的索

基于jQuery仿QQ音乐播放器网页版代码

基于jQuery仿QQ音乐播放器网页版代码是一款黑色样式风格的网页QQ音乐播放器样式代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class="m_player" id="divplayer" role="application" onselectstart="return false" style="left: 0px;"> <div class=&

jQuery仿QQ音乐播放器

本文通过Html+CSS+jQuery开发仿QQ版的音乐播放器,是前端技术的综合应用,所用素材来源于网络,仅供学习分享使用,如有不足之处,还请指正. 涉及知识点 在本例中用到的知识点如下,按jQuery和CSS进行区分: jQuery 是一个 JavaScript 库, 极大地简化了 JavaScript 编程,常见知识点如下: 通过标签获取jQuery对象:var $audio =$("audio"); 通过选择符获取jQuery对象并设置文本内容:$(".music_pr

swift 音乐播放器项目-《lxy的杰伦情歌》开发实战演练

最近准备将项目转化为OC与swift混合开发,试着写一个swift音乐播放器的demo,体会到了swift相对OC的优势所在,废话不多说,先上效果图: ps:身为杰伦的铁粉,demo的主题必须跟杰伦有关,哈哈!而且自我感觉我有转型UI的天赋,有木有? 一.导入OC文件 创建好swift项目之后,导入OC工具类文件,Xcode会自动生成桥接文件 打开这个文件,在开头导入OC工具类的头文件,就可以调用OC工具类了 // // Use this file to import your target's

Qt版音乐播放器

    Qt版音乐播放器 转载请标明出处:牟尼的专栏 http://blog.csdn.net/u012027907 一.关于Qt 1.1 什么是Qt Qt是一个跨平台应用程序和UI开发框架.使用Qt只需一次性开发应用程序,无需重新编写源代码,便可跨不同桌面和嵌入式操作系统部署这些应用程序. Qt Creator是全新的跨平台Qt IDE,可单独使用,也可与Qt库和开发工具组成一套完整的SDK,其中包括:高级C++代码编辑器,项目和集成管理工具,集成的上下文相关的帮助系统,图形化调试器,代码管理

用PHP+H5+Boostrap做简单的音乐播放器(进阶版)

前言:之前做了一个音乐播放器(纯前端),意外的受欢迎,然后有人建议我把后台一起做了,正好也想学习后台,所以学了两天php(不要吐槽我的速度,慢工出细活嘛~)然后在之前的基础上也又完善了一些功能,所以这个Demo比之前的可以算是进阶呢~v2.0哈哈哈~感觉截图体验很不好呢,所以在美图秀秀上面做了简易的动图,大家感受感受 正文: 老规矩,先上图~感觉有点卡,愿意等的就等等嘛,不愿意等的,往下看,有图片讲解 功能实现: 1.点击音乐列表播放音乐 2.拖动或点击进度条,调节音乐播放进度 3.浮动到音量控

新手作品~~~简单版音乐播放器

为了完成别人交给的小任务,作为一个新手看了很多的视频教程,实在是难死宝宝了,好在终于找到一篇合适我的布局的关于音乐播放器布局的文章,所以用了两天,就照猫画虎的学了下来,为了完全适配我的布局文件,删删减减,查了很多资料....才算是搞出个基本样子,废话不多说,直接上代码和效果图,新人作品,不喜勿喷. 功能很简单: 1.扫描sd卡内的音乐文件,将扫描到的音乐文件加载到音乐列表中. 2.点击音乐列表,实现播放音乐的功能 3.点击播放控制按钮(播放/暂停 上/下一曲)实现相关功能 首先是三个Java文件

Qt5 简单音乐播放器(进击版1)

今天又抽空改进了下音乐播放器的功能 主要改进代码: 播放列表:QListWidget 类 标准文件对话框:QFileDialog QString getfilename(QString filepath) {     QString filename;     QStringList list = filepath.split("/");     filename = list.at(list.size()-1);     return filename; } QString Main

android版音乐播放器----卡拉OK歌词实现(二)

相信大家都看过酷狗的音乐播放器,特别是酷狗的滚动歌词实现起来,效果特别好.我自己也尝试看了一下酷狗的歌词文件,发现是加密的,根本就看不了,所以只能是从目前开源的歌词文件出发了.我自己选择的是ksc歌词文件. 要实现歌词的功能,那首先就是要先认识一下ksc歌词的文件与普通的lrc歌词有那方面的区别? 当然,这里我从网上找了一个文档,看了文档里面的介绍,大家大概就会明白两都的区别. http://wenku.baidu.com/link?url=Ga4ESBrytlx3qUoxX5ApHbFIZro