Android初级,MediaPlayer播放音乐,进度条滑动及唱片转动功能实现

来源:互联网 发布:pl10空空导弹 知乎 编辑:程序博客网 时间:2024/05/16 15:04

最近在做仿网易云音乐播放器的实训项目,学习完后写此博客,一方面巩固自己理解,一方面方便各位浏览。
读完本文你将了解到:

  • 如何利用MediaPlayer播放音乐
  • 如何设置音乐进度条并实现自动滚动及手动定位
  • 如何实现唱片转动功能

1.效果图

这里写图片描述
这里写图片描述

2.代码如下

Layout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">//设置背景图片    <ImageView        android:id="@+id/listen_background_iv"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:scaleType="centerCrop"        android:src="@mipmap/img1" />    <RelativeLayout        android:id="@+id/listen_rl"        android:layout_width="match_parent"        android:layout_height="70dp"        android:layout_weight="1">//设置返回按钮图片        <ImageView            android:id="@+id/listen_back1_iv"            android:layout_width="30dp"            android:layout_height="30dp"            android:layout_alignParentStart="true"            android:layout_centerVertical="true"            android:layout_marginLeft="5dp"            android:src="@mipmap/back1" />//设置歌曲名        <TextView            android:id="@+id/listen_title_tv"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginLeft="15dp"            android:layout_marginTop="8dp"            android:layout_toRightOf="@id/listen_back1_iv"            android:text="成都"            android:textColor="#f9f7f7"            android:textSize="20sp" />//设置歌手名        <TextView            android:id="@+id/listen_artist_tv"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignStart="@id/listen_title_tv"            android:layout_below="@id/listen_title_tv"            android:layout_marginTop="5dp"            android:text="赵雷-"            android:textColor="#aeabab"            android:textSize="15sp" />//设置专辑名        <TextView            android:id="@+id/listen_album_tv"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignTop="@id/listen_artist_tv"            android:layout_toRightOf="@id/listen_artist_tv"            android:text="成都"            android:textColor="#aeabab"            android:textSize="15sp" />//设置“分享”按钮(本代码中未实现)        <ImageView            android:layout_width="30dp"            android:layout_height="30dp"            android:layout_alignParentEnd="true"            android:layout_centerVertical="true"            android:layout_marginRight="15dp"            android:src="@mipmap/share" />//设置布局间的线        <View            android:layout_width="match_parent"            android:layout_height="0.5dp"            android:layout_below="@id/listen_artist_tv"            android:background="#bababa" />    </RelativeLayout>//设置唱片圆盘    <ImageView        android:id="@+id/listen_changpian_img"        android:layout_width="250dp"        android:layout_height="250dp"        android:layout_centerHorizontal="true"        android:layout_centerVertical="true"        android:src="@mipmap/play_page_disc" />//设置圆盘上的指针    <ImageView        android:id="@+id/listen_zhizhen_iv"        android:layout_width="100dp"        android:layout_height="150dp"        android:layout_below="@id/listen_rl"        android:layout_centerHorizontal="true"        android:src="@mipmap/play_page_needle" />    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_alignParentStart="true"        android:layout_alignParentTop="true"        android:layout_marginBottom="15dp">        <RelativeLayout            android:id="@+id/listen_play"            android:layout_width="match_parent"            android:layout_height="60dp"            android:layout_alignParentBottom="true"            android:layout_marginBottom="0dp">//设置“暂停”            <ImageView                android:id="@+id/listen_pause1_img"                android:layout_width="60dp"                android:layout_height="60dp"                android:layout_centerHorizontal="true"                android:layout_centerVertical="true"                android:layout_marginTop="10dp"                android:src="@mipmap/icon_music_circle_pause" />//设置“上一首”            <ImageView                android:id="@+id/listen_back_img"                android:layout_width="40dp"                android:layout_height="40dp"                android:layout_centerVertical="true"                android:layout_marginLeft="30dp"                android:layout_marginRight="30dp"                android:layout_toLeftOf="@id/listen_pause1_img"                android:src="@mipmap/back_w" />//设置下一首            <ImageView                android:id="@+id/listen_next_img"                android:layout_width="40dp"                android:layout_height="40dp"                android:layout_centerVertical="true"                android:layout_marginLeft="30dp"                android:layout_toRightOf="@id/listen_pause1_img"                android:src="@mipmap/next_w" />        </RelativeLayout>        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_above="@id/listen_play"            android:layout_marginBottom="10dp"            android:orientation="horizontal"            android:paddingLeft="10dp"            android:paddingRight="10dp">//设置“当前歌曲时间”            <TextView                android:id="@+id/listen_current_tv"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="00:00" />//设置“进度条”            <SeekBar                android:id="@+id/listen_jindutiao_sb"                android:layout_width="0dp"                android:layout_height="match_parent"                android:layout_weight="1" />//设置“歌曲总时长”            <TextView                android:id="@+id/listen_length_tv"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="02:30" />        </LinearLayout>    </RelativeLayout></RelativeLayout>

MusicActivity

首先对需要用到的控件进行定义:

    private ImageView backIv;    private ImageView nextIv;//"下一首"    private ImageView discsmap;//"唱片"    private ImageView pauseIv;//“暂停”    private MediaPlayer mediaPlayer;//"MediaPlayer"    private ObjectAnimator animator;//运用ObjectAnimator实现转动    private TextView currentTv;//"当前时间"    private TextView totalTv;//“歌曲总时间”    private int totalTime;//“歌曲总时长,用于获取歌曲时长”    private SeekBar jindutiaoSb; //"进度条"    private boolean isStop;//“停止”    private int position;

新建方法link()进行绑定ID:

 private void Link() {        backIv = findViewById(R.id.listen_back_img);        nextIv = findViewById(R.id.listen_next_img);        discsmap = findViewById(R.id.listen_changpian_img);        pauseIv = findViewById(R.id.listen_pause1_img);        currentTv = findViewById(R.id.listen_current_tv);        totalTv = findViewById(R.id.listen_length_tv);        jindutiaoSb = findViewById(R.id.listen_jindutiao_sb);    }

新建play()方法用于歌曲播放、唱片打碟功能,及进度条简要设置

private void play() {        mediaPlayer.reset();//进行重置        Bitmap disces = BitmapFactory.decodeResource(getResources(), R.mipmap.circumstance);        }        /////////////////////歌曲播放////////////////////////////////////////////////////        try {            mediaPlayer.setDataSource(music.path);            mediaPlayer.prepare();            mediaPlayer.start();        } catch (IOException e) {            e.printStackTrace();        }        backIv.setOnClickListener(this);        nextIv.setOnClickListener(this);        pauseIv.setOnClickListener(this);        ///////////////////////////////////唱片打碟/////////////////////////////////////////////        animator = ObjectAnimator.ofFloat(discsmap, "rotation", 0f, 360.0f);        animator.setDuration(10000);        animator.setInterpolator(new LinearInterpolator());//匀速        animator.setRepeatCount(-1);//设置动画重复次数(-1代表一直转)        animator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式        animator.start();        ////////////////////////////////进度条/////////////////////////////////////////////////        totalTv.setText(formatTime(music.length));//获取歌曲时长并作为文本显示        totalTime = music.length;//获取歌曲时长        new Thread(new SeekBarThread()).start();//线程开始        jindutiaoSb.setMax(music.length);//设置音乐长度最大值,从而使音乐长度简单且可控        ////////////////////////////指针拨动////////////////////////////////////////////////////        animator1 = ObjectAnimator.ofFloat(zhizhenmap, "rotation", -60f, 0.0f);        animator1.setDuration(900);        animator1.setRepeatCount(0);//设置动画重复次数(-1代表一直转)        animator1.start();    }

获取歌曲时长并将其转化为“分:秒”形式:

 ///////////////规定需要的时间形式///////////////////////    private String formatTime(int length) {        Date date = new Date(length);//调用Date方法获值        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");//规定需要形式        String TotalTime = simpleDateFormat.format(date);//转化为需要形式        return TotalTime;    }

设置事件监听:

 @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.listen_back_img://当点击“上一首”按钮                position--;//数组递减                if (position == -1) {                    position = Common.musicList.size() - 1;                }                play();                break;            case R.id.listen_next_img:                position++;                if (position == Common.musicList.size()) {                    position = 0;                }                play();            case R.id.listen_pause1_img:                if (mediaPlayer.isPlaying()) {                    mediaPlayer.pause();//当正在播放时,点击“暂停”                    animator.pause();                    pauseIv.setImageResource(R.mipmap.start);                } else {                    mediaPlayer.start();//否则,播放                    pauseIv.setImageResource(R.mipmap.icon_music_circle_pause);                    animator.resume();                    animator1.resume();                }            default:                break;        }    }

建立销毁方法:

 @Override    protected void onDestroy() {        super.onDestroy();        mediaPlayer.reset();        isStop = true;    }

运用多线程进行进度条及位置更新:

class SeekBarThread implements Runnable {        @Override        public void run() {            while (mediaPlayer != null && isStop == false) {                // 将SeekBar位置设置到当前播放位置                handler.sendEmptyMessage(mediaPlayer.getCurrentPosition());                try {                    // 每100毫秒更新一次位置                    Thread.sleep(80);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }

定义Handler进行接收:

 private Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            jindutiaoSb.setProgress(msg.what);            currentTv.setText(formatTime(msg.what));        }    };

整体代码如下:

package com.example.listviewpagerviewdemo;public class MusicActivity extends AppCompatActivity implements View.OnClickListener {//定义各类控件    private ImageView backIv;    private ImageView nextIv;    private int position;    private ImageView discsmap;    private ImageView pauseIv;    private MediaPlayer mediaPlayer;    private ObjectAnimator animator;    private TextView currentTv;    private TextView totalTv;    private int totalTime;    private SeekBar jindutiaoSb;    private boolean isStop;    //接受多线程信息,安卓中不允许主线程实现UI更新    private Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            jindutiaoSb.setProgress(msg.what);            currentTv.setText(formatTime(msg.what));        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.listen_layout);//获取传值        Intent intent = getIntent();        position = intent.getIntExtra("i", 0);//将传入的值赋给position//获取mediaplayer        mediaPlayer = new MediaPlayer();        Link();//绑定ID方法        play();//歌曲播放及一系列操作方法/////////////////////////获取进度条点击位置并使歌曲跳转到该位置////////////////////////////////////        jindutiaoSb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {            @Override            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {                if (b) {                    mediaPlayer.seekTo(i);                }            }            @Override            public void onStartTrackingTouch(SeekBar seekBar) {            }            @Override            public void onStopTrackingTouch(SeekBar seekBar) {            }        });    }    private void play() {        mediaPlayer.reset();        Music music = Common.musicList.get(position);//获取传来的值        Bitmap disces = BitmapFactory.decodeResource(getResources(), R.mipmap.circumstance);        /////////////////////歌曲播放////////////////////////////////////////////////////        try {            mediaPlayer.setDataSource(music.path);            mediaPlayer.prepare();            mediaPlayer.start();        } catch (IOException e) {            e.printStackTrace();        }        backIv.setOnClickListener(this);        nextIv.setOnClickListener(this);        pauseIv.setOnClickListener(this);        ///////////////////////////////////唱片打碟/////////////////////////////////////////////        animator = ObjectAnimator.ofFloat(discsmap, "rotation", 0f, 360.0f);        animator.setDuration(10000);        animator.setInterpolator(new LinearInterpolator());//匀速        animator.setRepeatCount(-1);//设置动画重复次数(-1代表一直转)        animator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式        animator.start();        ////////////////////////////////进度条/////////////////////////////////////////////////        totalTv.setText(formatTime(music.length));        totalTime = music.length;        new Thread(new SeekBarThread()).start();        jindutiaoSb.setMax(music.length);        ////////////////////////////指针拨动////////////////////////////////////////////////////        animator1 = ObjectAnimator.ofFloat(zhizhenmap, "rotation", -60f, 0.0f);        animator1.setDuration(900);        animator1.setRepeatCount(0);//设置动画重复次数(-1代表一直转)        animator1.start();    }    ///////////////获取歌曲时常///////////////////////    private String formatTime(int length) {        Date date = new Date(length);        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");        String TotalTime = simpleDateFormat.format(date);        return TotalTime;    }    private void Link() {        backIv = findViewById(R.id.listen_back_img);        nextIv = findViewById(R.id.listen_next_img);        discsmap = findViewById(R.id.listen_changpian_img);        pauseIv = findViewById(R.id.listen_pause1_img);        currentTv = findViewById(R.id.listen_current_tv);        totalTv = findViewById(R.id.listen_length_tv);        jindutiaoSb = findViewById(R.id.listen_jindutiao_sb);    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.listen_back_img:                position--;                if (position == -1) {                    position = Common.musicList.size() - 1;                }                play();                break;            case R.id.listen_next_img:                position++;                if (position == Common.musicList.size()) {                    position = 0;                }                play();            case R.id.listen_pause1_img:                if (mediaPlayer.isPlaying()) {                    mediaPlayer.pause();                    animator.pause();                    pauseIv.setImageResource(R.mipmap.start);                } else {                    mediaPlayer.start();                    pauseIv.setImageResource(R.mipmap.icon_music_circle_pause);                    animator.resume();                    animator1.resume();                }            default:                break;        }    }    @Override    protected void onDestroy() {        super.onDestroy();        mediaPlayer.reset();        isStop = true;    }    class SeekBarThread implements Runnable {        @Override        public void run() {            while (mediaPlayer != null && isStop == false) {                // 将SeekBar位置设置到当前播放位置                handler.sendEmptyMessage(mediaPlayer.getCurrentPosition());                try {                    // 每100毫秒更新一次位置                    Thread.sleep(80);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}

Tip:

本文未将传入值进行代码讲解,仅对实现播放音乐、进度条滑动及唱片功能的实现进行了解析,需要注意的是,在除本文代码外我也单独地定义了一个工具类取名“Common”,用于存放Music类中定义的方法,在此也把代码给各位:

Common:

public class Common {    public static List<Music> musicList = new ArrayList<>();}

Music:

public class Music {    public int length;//歌曲长度    public  String  path;//歌曲获取路径}

除去获取歌曲的时长用setMax方法外,还有更偏重“小学数学好的人”的方法,即不采用获取setMax方法,而是将歌曲长度从毫秒用类型转换及计算转化为0-100内的整数:

            float c = msg.what;            jindutiaoSb.setProgress((int)(c/totalTime*100));
阅读全文
1 0
原创粉丝点击