仿QQ音乐播放界面(已实现主要功能)

 

源码地址:https://github.com/yeaper/MusicPlayer

因项目需要,实现的功能类似QQ音乐播放界面

 

使用 kotlin 代替 Java

 

主要功能:

1、播放、暂停音乐

2、自动、手动设置进度条,并且同步播放音乐

3、开启、暂停、停止匀速旋转的动画

 

先看效果图:

仿QQ音乐播放界面(已实现主要功能)_第1张图片     仿QQ音乐播放界面(已实现主要功能)_第2张图片

 

1、布局文件

 



    
    

    
        
        
            
            
        

        

        
            
            
            
        

        
            
            
            
        

        
            
            
            
        
    

    



主要用到 2 个第三方控件

 

 

(1)compile 'com.pkmmte.view:circularimageview:1.1'

(2)compile 'com.minimize.library:seekbar-compat:0.2.5'


其中,program_play_seekbar_bg.XML文件如下:

 

 

 

 



    
        
            
        
    
    
        
            
                
            
        
    
    
        
            
                
            
        
    


2、后台播放、暂停音乐服务类

 

 

class MusicPlayerService : Service() {

    private var mediaPlayer: MediaPlayer? = null

    override fun onBind(p0: Intent?): IBinder {
        return MyBinder()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        var action = ""
        var musicUrl = ""
        //获取意图传递的信息
        if(intent != null){
            action = intent.getStringExtra("action")
            musicUrl = intent.getStringExtra("musicUrl")
        }

        when (action) {
            "prepare" -> {
                if (mediaPlayer == null) {
                    mediaPlayer = MediaPlayer()
                    mediaPlayer!!.setAudioStreamType(AudioManager.STREAM_MUSIC)
                    mediaPlayer!!.setDataSource(musicUrl)
                    mediaPlayer!!.prepare()
                }
            }
            "play" -> {
                if (mediaPlayer == null) {
                    mediaPlayer = MediaPlayer()
                    mediaPlayer!!.setAudioStreamType(AudioManager.STREAM_MUSIC)
                    mediaPlayer!!.setDataSource(musicUrl)
                    mediaPlayer!!.prepare()
                }
                if (mediaPlayer != null && !mediaPlayer!!.isPlaying) {
                    mediaPlayer!!.start()
                }
            }
            "pause" -> {
                if (mediaPlayer != null && mediaPlayer!!.isPlaying) {
                    mediaPlayer!!.pause()
                }
            }
            "stop" -> {
                if (mediaPlayer != null && mediaPlayer!!.isPlaying) {
                    mediaPlayer!!.stop()
                }
            }
            "release" -> {
                if (mediaPlayer != null) {
                    mediaPlayer!!.stop()
                    mediaPlayer!!.release()
                    mediaPlayer = null
                }
            }
        }

        return super.onStartCommand(intent, flags, startId)
    }

    internal inner class MyBinder : Binder() {
        //获取歌曲长度
        fun getMusicDuration(): Int {
            var rtn = 0
            if (mediaPlayer != null) {
                rtn = mediaPlayer!!.duration
            }

            return rtn
        }

        //获取当前播放进度
        fun getMusicCurrentPosition(): Int {
            var rtn = 0
            if (mediaPlayer != null) {
                rtn = mediaPlayer!!.currentPosition
            }

            return rtn
        }

        fun seekTo(position: Int) {
            if (mediaPlayer != null) {
                mediaPlayer!!.seekTo(position)
            }
        }
    }
}


3、音乐播放类

 

 

class ProgramPlayActivity : BaseActivity() {

    var actionBar: ActionBar? = null
    var pastProgram: PastProgram? = null

    var serviceConnection: ServiceConnection? = null
    private var binder: MusicPlayerService.MyBinder? = null
    var isFinished = false // 是否结束当前activity的标志
    var isPlaying = false

    private var currentValue = 0f
    private var objAnim: ObjectAnimator? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_program_play)

        initToolbar()
        initInfo()
    }

    fun initToolbar(){
        setSupportActionBar(toolbar)

        actionBar = supportActionBar
        if (actionBar != null) {
            // 显示返回按钮
            actionBar!!.setDisplayHomeAsUpEnabled(true)
            // 隐藏 ActionBar 自带标题
            actionBar!!.setDisplayShowTitleEnabled(false)
        }
    }

    fun initInfo(){

        if(intent.extras != null){
            pastProgram = intent.getSerializableExtra("program") as PastProgram?
        }

        toolbar_title.text = pastProgram!!.name

        Picasso.with(this)
                .load(pastProgram!!.bgImageUrl)
                .placeholder(R.drawable.hdu_radio_header_bg)
                .into(programPlayHeaderBg)
        Picasso.with(this)
                .load(pastProgram!!.bgImageUrl)
                .placeholder(R.drawable.developer_fat)
                .into(programPlayRecordImage)
        programPlayLyric.text = "The truth that you leave-Pianoboy\n说了再见以后-苏打绿"
        programPlayName.text = pastProgram!!.name
        programPlayAnchor.text = "主播:罗焓智"
        programPlayDirector.text = "导播:"+pastProgram!!.director
        programPlayProducer.text = "监制:"+pastProgram!!.producer

        initRotateAnim()
        prepareMediaPlayer()
        setListener()
    }

    /**
     * 准备播放器
     */
    fun prepareMediaPlayer(){
        val intent = Intent(this, MusicPlayerService::class.java)
        intent.putExtra("action", "prepare")
        intent.putExtra("musicUrl", pastProgram!!.audioUrl)
        startService(intent)

        if (serviceConnection == null) {
            serviceConnection = object : ServiceConnection {
                override fun onServiceConnected(name: ComponentName, service: IBinder) {

                    binder = service as MusicPlayerService.MyBinder

                    // 设置进度条的最大长度
                    programPlayProgressBar.max = binder!!.getMusicDuration()
                    // 设置歌曲总时长
                    programPlayEndTime.text = msecToPlayTime(binder!!.getMusicDuration())

                    programPlayProgressBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                        override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
                            // 手动控制进度
                            if(fromUser){
                                binder!!.seekTo(progress)
                            }
                            // 播放结束后,还原状态
                            if(progress == seekBar.max){
                                binder!!.seekTo(0)
                                val msg = handler.obtainMessage()
                                msg.what = 3
                                handler.sendMessage(msg)
                            }
                        }

                        override fun onStartTrackingTouch(seekBar: SeekBar) {

                        }

                        override fun onStopTrackingTouch(seekBar: SeekBar) {

                        }
                    })

                    // 连接之后启动子线程设置当前进度
                    object : Thread() {
                        override fun run() {
                            while (true) {

                                if(isFinished){
                                    break
                                }

                                // 改变当前进度条的值
                                val msg1 = handler.obtainMessage()
                                msg1.what = 1
                                msg1.arg1 = binder!!.getMusicCurrentPosition()
                                handler.sendMessage(msg1)

                                // 改变起始时间
                                val msg2 = handler.obtainMessage()
                                msg2.what = 2
                                msg2.obj = msecToPlayTime(binder!!.getMusicCurrentPosition())
                                handler.sendMessage(msg2)

                                try {
                                    Thread.sleep(100)
                                } catch (e: Exception) {
                                    e.printStackTrace()
                                }
                            }
                        }
                    }.start()
                }

                override fun onServiceDisconnected(name: ComponentName) {

                }
            }

            // 以绑定方式连接服务
            bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
        }
    }

    fun setListener(){
        programPlayStart.setOnClickListener {
            playPause()
        }
        programPlayPrevious.setOnClickListener {

        }
        programPlayNext.setOnClickListener {

        }
    }

    private var handler = object : Handler() {
        override fun handleMessage(msg: Message?) {
            when(msg!!.what){
                1 -> {
                    programPlayProgressBar.progress = msg.arg1
                }
                2 -> {
                    programPlayStartTime.text = msg.obj as String
                }
                3 -> {
                    resetPlay()
                }
            }
        }
    }

    /**
     * 开启动画
     */
    fun startAnimation() {
        // 设置动画,从上次停止位置开始,这里是顺时针旋转360度
        objAnim = ObjectAnimator.ofFloat(programPlayRecordImage, "Rotation",
                currentValue - 360, currentValue)
        // 设置持续时间
        objAnim!!.duration = 30000
        // 设置循环播放
        objAnim!!.repeatCount = ObjectAnimator.INFINITE
        // 设置匀速播放
        val lin: LinearInterpolator = LinearInterpolator()
        objAnim!!.interpolator = lin
        // 设置动画监听
        objAnim!!.addUpdateListener({ animation ->
            // 监听动画执行的位置,以便下次开始时,从当前位置开始
            currentValue = animation.animatedValue as Float
        })
        objAnim!!.start()
    }

    /**
     * 停止动画
     */
    fun stopAnimation() {
        objAnim!!.end()
        currentValue = 0f // 重置起始位置
    }

    /**
     * 暂停动画
     */
    fun pauseAnimation() {
        objAnim!!.cancel()
    }

    /**
     * 播放、暂停音乐
     */
    fun playPause(){
        if(!isPlaying){
            isPlaying = true
            programPlayStart.setImageResource(R.drawable.program_play_pause)
            // 开启图片旋转动画
            startAnimation()

            val intent = Intent(this, MusicPlayerService::class.java)
            intent.putExtra("action", "play")
            intent.putExtra("musicUrl", pastProgram!!.audioUrl)
            startService(intent)
        }else {
            isPlaying = false
            programPlayStart.setImageResource(R.drawable.program_play_start)
            // 暂停动画
            pauseAnimation()

            val intent = Intent(this, MusicPlayerService::class.java)
            intent.putExtra("action", "pause")
            intent.putExtra("musicUrl", pastProgram!!.audioUrl)
            startService(intent)
        }
    }

    /**
     * 还原到音乐起始状态
     */
    fun resetPlay(){
        isPlaying = false
        programPlayStart.setImageResource(R.drawable.program_play_start)
        programPlayProgressBar.progress = 0
        programPlayStartTime.text = "00:00"
        // 关闭动画
        stopAnimation()

        val intent = Intent(this, MusicPlayerService::class.java)
        intent.putExtra("action", "pause")
        intent.putExtra("musicUrl", pastProgram!!.audioUrl)
        startService(intent)
    }

    /**
     * 毫秒转换为播放时间
     */
    fun msecToPlayTime(time: Int): String{
        var min = time.div(60000).toString()
        var second = time.mod(60000).div(1000).toString()
        if(min.toInt() < 10){
            min = "0"+min
        }
        if(second.toInt() < 10){
            second = "0"+second
        }

        return min+":"+second
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.toolbar_transport_menu, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            android.R.id.home -> { finish() }
            R.id.program_play_music_list -> {}
        }

        return super.onOptionsItemSelected(item)
    }

    override fun onDestroy() {
        super.onDestroy()
        // 停止更新UI
        isFinished = true
        // 关闭播放器,解绑服务
        val intent = Intent(this, MusicPlayerService::class.java)
        intent.putExtra("action", "release")
        intent.putExtra("musicUrl", pastProgram!!.audioUrl)
        startService(intent)
        unbindService(serviceConnection)
    }
}


有具体问题,可以留言讨论!!

 

 

 

你可能感兴趣的:(Android开发实战,Android笔记)