升级版音乐播放器

来源:互联网 发布:程序员面试问题及答案 编辑:程序博客网 时间:2024/05/22 04:31

每天写个APP_第2天——升级版音乐播放器

android 音乐播放器 SeekBar Runnable


前面的话

:有同学说我写的不够详细,我以后会注意和完善。又说能否有源码,我一般会在文章里贴出所有源码,另外我今天会吧代码传到github上提供下载。

回顾:上篇文章实现各一个简单的播放器,但是仍然不是很酷。今天,我们对它做个改进。还记得网易云音乐APP中播放界面有个CD吗?当播放音乐时,中间的CD就会转动,是不是很酷?今天我们也把中间的CD转起来!然后,我们还要添加歌曲进度条,还可以用手指拖动进度条实现歌曲的指定播放位置。

改进点:

  • 实现CD唱片的转动!
  • 添加歌曲进度条

编程关键词

  • SeekBar类
  • Runnable类
  • Animation类
  • xml:rotate

界面



转动吧!CD

Android 平台提供了两类动画,一类是 Tween 动画,即通过对场景里的对象不断做图像变换(平移、缩放、旋转)产生动画效果;第二类是 Frame 动画,即顺序播放事先做好的图像,跟电影类似。这里我们使用 Tween动画的rotate实现旋转效果。

rotate.xml

在res文件夹新建anim文件夹,在里面新建rotae.xml

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android">    <rotate         android:fromDegrees="0"        android:toDegrees="359"        android:pivotX="50%"        android:pivotY="50%"        android:repeatCount="-1"        android:duration="4500"        /></set>

解析:从0到359度开始循环旋转,0-359(若设置成360在停止时会出现停顿现象)度旋转所用时间为500ms,旋转中心距离view的左顶点为50%距离,距离view的上边缘为50%距离,即正中心,具体每个含义见下面的具体属性介绍。

android:fromDegrees 起始的角度度数

android:toDegrees 结束的角度度数,负数表示逆时针,正数表示顺时针。如10圈则比android:fromDegrees大3600即可

android:pivotX 旋转中心的X坐标 
浮点数或是百分比。浮点数表示相对于Object的左边缘,如5; 百分比表示相对于Object的左边缘,如5%; 另一种百分比表示相对于父容器的左边缘,如5%p; 一般设置为50%表示在Object中心

android:pivotY 旋转中心的Y坐标 
浮点数或是百分比。浮点数表示相对于Object的上边缘,如5; 百分比表示相对于Object的上边缘,如5%; 另一种百分比表示相对于父容器的上边缘,如5%p; 一般设置为50%表示在Object中心

android:duration 表示从android:fromDegrees转动到android:toDegrees所花费的时间,单位为毫秒。可以用来计算速度。

android:interpolator表示变化率,但不是运行速度。一个插补属性,可以将动画效果设置为加速,减速,反复,反弹等。默认为开始和结束慢中间快,

android:startOffset 在调用start函数之后等待开始运行的时间,单位为毫秒,若为10,表示10ms后开始运行

android:repeatCount 重复的次数,默认为0,必须是int,可以为-1表示不停止

android:repeatMode 重复的模式,默认为restart,即重头开始重新运行,可以为 
reverse即从结束开始向前重新运行。在android:repeatCount大于0或为infinite时生效

android:detachWallpaper 表示是否在壁纸上运行

android:zAdjustment 表示被animated的内容在运行时在z轴上的位置,默认为 
normal。

normal保持内容当前的z轴顺序

top运行时在最顶层显示

bottom运行时在最底层显示

具体参考我转载的文章:点击进入 
哪里用的到:没见过刷新转圈的动画吗

在java里调用

animation=AnimationUtils.loadAnimation(this, R.anim.rotate);        //设置匀速LinearInterpolator linearInterpolator=new LinearInterpolator();animation.setInterpolator(linearInterpolator);

SeekBar!

音乐播放是MediaPlayer这个类控制的,进度条SeekBar可以用来显示播放进度,用户也可以利用SeekBar的滑块来控制音乐的播放。两个按钮一个用来播放歌曲启动线程,另一个取消线程和停止播放歌曲。

SeekBar:

设置滑块的位置方法为:setProgress(int value);

设置最大值的方法为:setMax(int value);

MusicPlayer:

播放音乐方法为:start();

停止音乐播放的方法为:stop();

控制音乐播放位置为:seekTo(int value);

获得音乐长度为:getDuration(); 

获得现在播放的位置:getCurrentPosition();

Handler:

启动线程:post(Runnable runnable);

取消线程:removeCallbacks(Runnable runnable);

延迟启动线程(time 单位为毫秒):postDelayed(Runnable, int time);

MainActivity.java

本代码较于上篇的代码,针OOP思想做了些改善。注意SeekBar监听器的代码,你想写个老式卡带播放机子或是留声机吗?看看吧!

package com.example.playerofmusic;import android.app.Activity;import android.media.MediaPlayer;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.view.Window;import android.view.animation.Animation;import android.view.animation.AnimationUtils;import android.view.animation.LinearInterpolator;import android.view.animation.RotateAnimation;import android.widget.Button;import android.widget.EditText;import android.widget.ImageView;import android.widget.SeekBar;import android.widget.SeekBar.OnSeekBarChangeListener;import android.widget.TextView;import java.io.IOException;import java.util.Timer;import java.util.TimerTask;import com.example.playerofmusic.R.anim;public class MainActivity extends Activity {    private ImageView songImage;    private TextView songText;    private Button songStart;    private Button songStop;    private Button songPause;    private EditText editSongName;    private MediaPlayer musicPlayer;    //----------------以下是新添代码----------    private Handler handler;    private SeekBar songSeekBar;    private Animation animation;//使用动画类    private Runnable seekBarThread;    //------------------------------------    /*     * 也可用Timer类和TimerTask类实现SeekBar的持续移动     */    /*private Timer mTimer;        private TimerTask mTimerTask;     private boolean isChanging;*/    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        /*         * //设置为NoTitle,没有标题栏,上篇在清单文件中,添加的         * theme属性。         */        requestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.activity_main);        findView();//绑定控件        setListener();        SongImageAnim();        musicPlayer= new MediaPlayer();//实例化MediaPlayer        handleSongImageAnim();        songSeekBarProgress();//开启线子程控制seekbar跟随歌曲的进度    }    private void songSeekBarProgress() {        // TODO Auto-generated method stub        seekBarThread=new Runnable() {            @Override            public void run() {                // TODO Auto-generated method stub                //10毫秒执行以下线程,目的是持续改变SeekBar的位置                songSeekBar.setProgress(musicPlayer.getCurrentPosition());                handler.postDelayed(seekBarThread, 10);            }        };    }    private void handleSongImageAnim() {        // TODO Auto-generated method stub        //用handler来处理图片的旋转        handler=new Handler(){            @Override            public void handleMessage(Message msg) {                // TODO Auto-generated method stub                super.handleMessage(msg);                if(msg.what==1){//姑且设what为1                    if(animation!=null&&musicPlayer.isPlaying()){                        songImage.startAnimation(animation);                    }                }else{                    if(animation!=null){                        songImage.clearAnimation();                    }                }            }        };    }    private void SongImageAnim() {        // TODO Auto-generated method stub        animation=AnimationUtils.loadAnimation(this, R.anim.rotate);        //设置匀速        LinearInterpolator linearInterpolator=new LinearInterpolator();        animation.setInterpolator(linearInterpolator);    }    private void setListener() {        // TODO Auto-generated method stub        //为三个按钮设置监听器        songPause.setOnClickListener(new ButtonListener());        songStop.setOnClickListener(new ButtonListener());        songStart.setOnClickListener(new ButtonListener());        songSeekBar.setOnSeekBarChangeListener(new SongSeekBarListener());    }    private void findView() {        // TODO Auto-generated method stub        songImage=(ImageView)findViewById(R.id.image_songImage);        songText=(TextView)findViewById(R.id.text_songName);        editSongName=(EditText)findViewById(R.id.edit_songName);        songSeekBar=(SeekBar) findViewById(R.id.seekBar_song);        songStart=(Button)findViewById(R.id.button_start);        songStop=(Button)findViewById(R.id.button_stop);        songPause=(Button)findViewById(R.id.button_pause);    }    private class ButtonListener implements View.OnClickListener{        @Override        public void onClick(View view) {            try{//这里需要处理异常                switch (view.getId()){                    case R.id.button_start:                        //文件名                        String fileName=editSongName.getText().toString();                        songText.setText(fileName);                        //恢复原始界面                        if(songPause.getText().equals("继续")){                            songPause.setText("暂停");                        }                        //重置                        musicPlayer.reset();                        //文件路径                        musicPlayer.setDataSource("/sdcard/netease/cloudmusic/Music/"+fileName+".mp3");                        musicPlayer.prepare();                        musicPlayer.start();                        handler.sendEmptyMessage(1);                        songSeekBar.setMax(musicPlayer.getDuration());//设置进度条                          handler.post(seekBarThread);                        /*mTimer = new Timer();                            mTimerTask = new TimerTask() {                                @Override                                public void run() {                                     if(isChanging==true) {                                       return;                                    }                                  songSeekBar.setProgress(musicPlayer.getCurrentPosition());                              }                            };                         mTimer.schedule(mTimerTask, 0, 10); */                            break;                    case R.id.button_stop:                        musicPlayer.stop();                        songPause.setText("暂停");                        handler.sendEmptyMessage(2);//                        songSeekBar.setProgress(0);                        handler.removeCallbacks(seekBarThread);                        break;                    case R.id.button_pause:                        //注意界面的更改                        if(musicPlayer.isPlaying()){                            musicPlayer.pause();                            ((Button)view).setText("继续");                            handler.sendEmptyMessage(2);                            handler.post(seekBarThread);                        }else{                            musicPlayer.start();                            handler.sendEmptyMessage(1);                            ((Button)view).setText("暂停");                        }                        break;                }            }catch (IOException e){                e.printStackTrace();            }        }    }    class SongSeekBarListener implements OnSeekBarChangeListener{        @Override        public void onProgressChanged(android.widget.SeekBar arg0, int progress,                boolean fromUser) {            // TODO Auto-generated method stub            if(fromUser==true){                if(musicPlayer.isPlaying())                musicPlayer.pause();                musicPlayer.seekTo(progress);                //如果在这里start(),效果就像老式卡带机或是留声机,不信你试试                //musicPlayer.start();            }        }        @Override        public void onStartTrackingTouch(android.widget.SeekBar arg0) {            // TODO Auto-generated method stub            //isChanging=true;        }        @Override        public void onStopTrackingTouch(android.widget.SeekBar arg0) {            // TODO Auto-generated method stub            //musicPlayer.seekTo(songSeekBar.getProgress());              //isChanging=false;             //当手指抬起时,开始从歌曲新的位置播放歌曲            if(!musicPlayer.isPlaying())                musicPlayer.start();        }    }    @Override    protected void onPause() {        super.onPause();        if(musicPlayer!=null){            if(musicPlayer.isPlaying())                musicPlayer.stop();        }    }    @Override    protected void onResume() {        super.onResume();        if(musicPlayer!=null){            if(musicPlayer.isPlaying())                musicPlayer.start();        }    }    @Override    protected void onDestroy() {        super.onDestroy();        if(musicPlayer!=null){            if(musicPlayer.isPlaying())                musicPlayer.stop();            musicPlayer.release();        }        if(animation!=null){            songImage.clearAnimation();        }        handler.removeCallbacks(seekBarThread);    }}

界面xml

做了一些小改动。

<RelativeLayout     xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#ff646469"    tools:context=".MainActivity">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical"        android:weightSum="1">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center"            android:paddingTop="15dp"            android:textSize="35sp"            android:textColor="#fff"            android:text="音乐播放器"/>        <TextView            android:layout_marginTop="22dp"            android:id="@+id/text_songName"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center"            android:textColor="#fff"            android:textSize="19sp"            android:text="好妹妹"/>        <ImageView            android:layout_marginTop="18dp"            android:id="@+id/image_songImage"            android:layout_width="290dp"            android:layout_height="290dp"            android:layout_gravity="center"            android:src="@drawable/ico2"/>        <SeekBar             android:layout_marginTop="20dp"            android:id="@+id/seekBar_song"            android:max="100"            android:layout_width="300dp"            android:layout_height="wrap_content"            android:layout_gravity="center_horizontal"/>        <EditText            android:layout_gravity="center"            android:id="@+id/edit_songName"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:hint="输入歌曲名"/>        <LinearLayout            android:layout_marginTop="20dp"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="horizontal"            >            <Button                android:id="@+id/button_pause"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_weight="3.333"                android:textColor="#fff"                android:text="暂停"/>            <Button                android:id="@+id/button_start"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_weight="3.333"                android:textColor="#fff"                android:text="播放"/>            <Button                android:id="@+id/button_stop"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_weight="3.333"                android:textColor="#fff"                android:text="停止"/>        </LinearLayout>    </LinearLayout></RelativeLayout>

明天的APP

明天继续完善这个音乐播放器,1.美化按钮2.播放网络上的音乐

2 0
原创粉丝点击