
UI界面模仿QQ音乐
实现一个简单的本地播放器,功能包括:播放,暂停,上一曲,下一曲,进度条。
功能实现
读取本地音乐
1.创建一个Song类
public class Song {public String song;//歌曲名public String singer;//歌手public long size;//歌曲所占空间大小public int duration;//歌曲时间长度public String path;//歌曲地址public String album;//专辑名
}
2.用于获取本地音乐的Utils
public class Utils {//定义一个集合,存放从本地读取到的内容public static List<Song> list;public static Song song;public static List<Song> getmusic(Context context) {list = new ArrayList<>();Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null, null, null, MediaStore.Audio.AudioColumns.IS_MUSIC);if (cursor != null) {while (cursor.moveToNext()) {song = new Song();song.song = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));song.album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));song.singer = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));song.path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));song.duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));song.size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));//把歌曲名字和歌手切割开if (song.size > 1000 * 800) {if (song.song.contains("-")) {String[] str = song.song.split("-");song.singer = str[0];song.song = str[1];}list.add(song);}}}cursor.close();return list;}// 转换歌曲时间的格式public static String formatTime(int time) {if (time / 1000 % 60 < 10) {String tt = time / 1000 / 60 + ":0" + time / 1000 % 60;return tt;} else {String tt = time / 1000 / 60 + ":" + time / 1000 % 60;return tt;}}
}
3.在布局里面定义一个ListView,并写一个适配器
//适配器class MyAdapter extends BaseAdapter {Context context;List<Song> list;private int mSelect; //选中项public MyAdapter(MainActivity mainActivity, List<Song> list) {this.context = mainActivity;this.list = list;}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int i) {return list.get(i);}@Overridepublic long getItemId(int i) {return i;}@Overridepublic View getView(int i, View view, ViewGroup viewGroup) {Myholder myholder;if (view == null) {myholder = new Myholder();view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.text, null);// myholder.t_position = view.findViewById(R.id.t_postion);myholder.t_song = view.findViewById(R.id.t_song);myholder.t_singer = view.findViewById(R.id.t_singer);myholder.t_blank=view.findViewById(R.id.t_blank);myholder.t_albumn=view.findViewById(R.id.t_albumn);myholder.t_point=view.findViewById(R.id.t_point);myholder.t_duration = view.findViewById(R.id.t_duration);view.setTag(myholder);} else {myholder = (Myholder) view.getTag();}myholder.t_song.setText(list.get(i).song.toString());myholder.t_singer.setText(list.get(i).singer.toString());String time = Utils.formatTime(list.get(i).duration);myholder.t_albumn.setText(list.get(i).album.toString());myholder.t_duration.setText(time);//myholder.t_position.setText(i + 1 + "");//设置相关数据if (mSelect==-1){myholder.t_song.setEnabled(true);myholder.t_singer.setEnabled(true);myholder.t_blank.setVisibility(View.INVISIBLE);//选中项背景myholder.t_song.setTextColor(getResources().getColor(R.color.tilte_color));myholder.t_singer.setTextColor(getResources().getColor(R.color.tilte_color));myholder.t_albumn.setTextColor(getResources().getColor(R.color.tilte_color));myholder.t_point.setTextColor(getResources().getColor(R.color.tilte_color));}if (mSelect == i) {myholder.t_song.setEnabled(true);myholder.t_singer.setEnabled(true);myholder.t_blank.setVisibility(View.VISIBLE);//选中项背景myholder.t_song.setTextColor(getResources().getColor(R.color.theme));myholder.t_singer.setTextColor(getResources().getColor(R.color.theme));myholder.t_albumn.setTextColor(getResources().getColor(R.color.theme));myholder.t_point.setTextColor(getResources().getColor(R.color.theme));myholder.t_duration.setTextColor(getResources().getColor(R.color.theme));} else {myholder.t_song.setEnabled(false);myholder.t_singer.setEnabled(false);myholder.t_blank.setVisibility(View.INVISIBLE);//其他项背景myholder.t_song.setTextColor(getResources().getColor(R.color.tilte_color));myholder.t_singer.setTextColor(getResources().getColor(R.color.song));myholder.t_albumn.setTextColor(getResources().getColor(R.color.song));myholder.t_point.setTextColor(getResources().getColor(R.color.song));myholder.t_duration.setTextColor(getResources().getColor(R.color.song));}return view;}class Myholder {ImageView t_blank;TextView t_position, t_song, t_singer, t_duration,t_albumn,t_point;}//刷新方法public void changeSelected(int positon){if (positon != mSelect) {mSelect = positon;notifyDataSetChanged();}}}
在类里面定义一个刷新位置的方法changeSelectde与ListView的点击监听事件配合使用,用于ListView被点击后将position参数传入,相应的文字颜色的改变
4.给ListView设置适配器
mylist = (ListView) findViewById(R.id.mylist);list = new ArrayList<>();list = Utils.getmusic(this);//获取音乐myAdapter = new MyAdapter(this, list);mylist.setAdapter(myAdapter);
5.使用MediaPlayer播放音乐
把音乐读取到ListView之后,点击音乐列表的音乐,就能够进行音乐的播放,并在底栏显示相应的音乐名,歌手名,可以拖动进度条进行音乐的控制,点击相应的按钮能够暂停,上一曲,下一曲。
首先封装一个播放音乐的方法,传入的参数currentPosition为音乐的位置
private void musicPlay(int currentPosition) {seekBar.setMax(list.get(currentPosition).getDuration());try {// 重置音频文件,防止多次点击会报错mediaPlayer.reset();//调用方法传进播放地址mediaPlayer.setDataSource(list.get(currentPosition).getPath());//异步准备资源,防止卡顿mediaPlayer.prepareAsync();//调用音频的监听方法,音频准备完毕后响应该方法进行音乐播放mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mediaPlayer) {mediaPlayer.start();//开始播放Thread thread = new Thread(new SeekBarThread());//更新SeekBar的线程thread.start();}});} catch (Exception e) {e.printStackTrace();}}
然后为ListView设置点击事件
mylist.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {currentPosition=position;musicPlay(currentPosition);//播放音乐myAdapter.changeSelected(currentPosition);//设置字体变色play.setVisibility(View.INVISIBLE);//播放按钮消失pause.setVisibility(View.VISIBLE);//暂停按钮出现String song=list.get(currentPosition).song;//获取音乐名String singer=list.get(currentPosition).singer;//获取歌手名bottomSong.setText(song);//底栏显示音乐名bottomSinger.setText(singer);//底栏显示歌手名gang.setVisibility(View.VISIBLE);//横杠}});
播放,暂停,上一曲,下一曲按钮点击事件
//暂停按钮pause.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mediaPlayer.pause();//暂停音乐pause.setVisibility(View.INVISIBLE);play.setVisibility(View.VISIBLE);}});//播放按钮play.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {play.setVisibility(View.INVISIBLE);pause.setVisibility(View.VISIBLE);mediaPlayer.start();//播放音乐}});/*** 下一曲*/next.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {currentPosition++;if (currentPosition > list.size() - 1) {currentPosition = 0;}musicPlay(currentPosition);myAdapter.changeSelected(currentPosition);//ListView颜色变化//底栏设置正在播放的歌曲信息String song=list.get(currentPosition).song;String singer=list.get(currentPosition).singer;bottomSong.setText(song);bottomSinger.setText(singer);gang.setVisibility(View.VISIBLE);}});/*** 上一曲*/pre.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {currentPosition--;if (currentPosition < 0) {currentPosition = list.size() - 1;}musicPlay(currentPosition);myAdapter.changeSelected(currentPosition);//ListView颜色变化//底栏设置正在播放的歌曲信息String song=list.get(currentPosition).song;String singer=list.get(currentPosition).singer;bottomSong.setText(song);bottomSinger.setText(singer);gang.setVisibility(View.VISIBLE);}});
给mediaPlayer添加一个监听事件,实现当前音乐播放完成后自动播放下一首的功能
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {currentPosition++;if (currentPosition > list.size() - 1) {currentPosition = 0;}musicPlay(currentPosition);myAdapter.changeSelected(currentPosition);//底栏设置正在播放的歌曲信息String song=list.get(currentPosition).song;String singer=list.get(currentPosition).singer;bottomSong.setText(song);bottomSinger.setText(singer);gang.setVisibility(View.VISIBLE);}});
5.进度条
使用Handler类,进行SeekBar的更新
private static final int UPDATE_SEEKBAR=0;private Handler handler=new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case UPDATE_SEEKBAR:// 将SeekBar位置设置到当前播放位置seekBar.setProgress(mediaPlayer.getCurrentPosition());break;default:break;}}};
定义一个类,实现Runnable接口进行SeekBar状态的刷新
class SeekBarThread implements Runnable {@Overridepublic void run() {while (mediaPlayer.isPlaying()) {try {// 每500毫秒更新一次位置Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}Message message=new Message();message.what=UPDATE_SEEKBAR;handler.sendMessage(message);}}}
给SeekBar添加监听事件,实现拖动进度条改变音乐进度
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {if(fromUser==true){mediaPlayer.seekTo(progress);}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {}});}
源码下载链接:
下载链接