码迷,mamicode.com
首页 > 其他好文 > 详细

欢迎使用CSDN-markdown编辑器

时间:2015-02-13 16:45:42      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:android   app   github上   音乐播放器   

每天写个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.播放网络上的音乐
- 功能丰富 :支持高亮代码块、LaTex 公式、流程图,本地图片上传甚至截图粘贴,工作学习好帮手;
- 得心应手 :简洁高效的编辑器,提供桌面[离线客户端][1],支持移动端 Web;
- 深度整合 :支持选择笔记本和添加标签,支持从印象笔记跳转编辑,轻松管理。


欢迎使用CSDN-markdown编辑器

标签:android   app   github上   音乐播放器   

原文地址:http://blog.csdn.net/c_major/article/details/43794221

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!