每天写个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.播放网络上的音乐