最近闲下来做了个仿网易云音乐的音乐播放器
效果图:

项目下载地址

https://github.com/PangHaHa12138/MusicPlayerdemo

闪屏


扫描本地音乐

播放


仿探探

仿ofo

仿摩拜

小鱼儿

自带 68首 老罗的相声节目(超搞笑)

闪屏

//放大图片public void animateImage() {ObjectAnimator animatorX = ObjectAnimator.ofFloat(splash, "scaleX", 1f,1.2f);ObjectAnimator animatorY = ObjectAnimator.ofFloat(splash, "scaleY", 1f,1.2f);AnimatorSet set = new AnimatorSet();set.setDuration(2000).play(animatorX).with(animatorY);set.start();set.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {startActivity(new Intent(Splash.this, MainActivity.class));Splash.this.finish();overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);}});}

发现音乐

主框架是由底部bottomNavigationBar+fragment构成
部分代码:

bottomNavigationBar.setMode(BottomNavigationBar.MODE_FIXED).setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC);bottomNavigationBar //值得一提,模式跟背景的设置都要在添加tab前面,不然不会有效果。.setActiveColor(R.color.white)//选中颜色 图标和文字.setInActiveColor("#8e8e8e")//默认未选择颜色.setBarBackgroundColor("#000000");//默认背景色bottomNavigationBar.addItem(new BottomNavigationItem(R.drawable.t_actionbar_discover_selected,"发现音乐")).addItem(new BottomNavigationItem(R.drawable.t_actionbar_music_selected,"我的音乐")).addItem(new BottomNavigationItem(R.drawable.t_actionbar_friends_selected,"朋友")).addItem(new BottomNavigationItem(R.drawable.tl,"我")).initialise();//所有的设置需在调用该方法前完成bottomNavigationBar //设置lab点击事件.setTabSelectedListener(new BottomNavigationBar.OnTabSelectedListener() {@Overridepublic void onTabSelected(int position) {android.support.v4.app.FragmentManager fr = getSupportFragmentManager();android.support.v4.app.FragmentTransaction ft = fr.beginTransaction();switch (position){case 0:ft.show(fragment_a).hide(fragment_b).hide(fragment_c).hide(fragment_d);title.setText("发现音乐");break;case 1:ft.show(fragment_b).hide(fragment_a).hide(fragment_c).hide(fragment_d);title.setText("我的音乐");break;case 2:ft.show(fragment_c).hide(fragment_b).hide(fragment_a).hide(fragment_d);title.setText("朋友");break;case 3:ft.show(fragment_d).hide(fragment_b).hide(fragment_c).hide(fragment_a);title.setText("我");break;}ft.commit();}@Overridepublic void onTabUnselected(int position) {}@Overridepublic void onTabReselected(int position) {}});

轮播图

 HashMap<String,Integer> file_maps = new HashMap<String, Integer>();file_maps.put("美丽又可爱",R.drawable.yut1);file_maps.put("语瞳小仙女",R.drawable.yut2);file_maps.put("活好还不黏",R.drawable.yut3);file_maps.put("人美声音甜", R.drawable.yut4);for(String name : file_maps.keySet()){TextSliderView textSliderView = new TextSliderView(getActivity());// initialize a SliderLayouttextSliderView.description(name).image(file_maps.get(name)).setScaleType(BaseSliderView.ScaleType.FitCenterCrop).setOnSliderClickListener(this);//add your extra informationtextSliderView.bundle(new Bundle());textSliderView.getBundle().putString("extra",name);mDemoSlider.addSlider(textSliderView);}mDemoSlider.setPresetTransformer(SliderLayout.Transformer.Accordion);mDemoSlider.setPresetIndicator(SliderLayout.PresetIndicators.Right_Bottom);mDemoSlider.setCustomAnimation(new DescriptionAnimation());mDemoSlider.setDuration(4000);mDemoSlider.addOnPageChangeListener(this);

瀑布流

 recyclerView = (RecyclerView) mview.findViewById(R.id.recycleview);StaggeredGridLayoutManager layoutManager =//这里 3 代表三列 后面代表瀑布流朝向new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);initlist();//初始化模拟数据mDemoSlider = (SliderLayout) mview.findViewById(R.id.slider);MeiziAdapter adapter = new MeiziAdapter(list,getActivity());recyclerView.setLayoutManager(layoutManager);recyclerView.setAdapter(adapter);SpcaceDecoration sc = new SpcaceDecoration(1);//设置间距recyclerView.addItemDecoration(sc);recyclerView.setNestedScrollingEnabled(false);//NesterScrollView不允许滑动recyclerView.setHasFixedSize(true);//RecycleView固定大小会实现优化adapter.setOnItemClickListener(new MeiziAdapter.OnItemClickListener() {@Overridepublic void onItemClick(View view, int position) {Toast.makeText(getActivity(),"我被点击了"+position,Toast.LENGTH_SHORT).show();}});

我的音乐

旋转图片

  rotateAnimation = new RotateAnimation(0f,360f, Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);LinearInterpolator lin = new LinearInterpolator();rotateAnimation.setInterpolator(lin);//匀速rotateAnimation.setDuration(8000);//设置动画持续时间rotateAnimation.setRepeatCount(-1);//设置重复次数 -1不停rotateAnimation.setFillAfter(true);//动画执行完后是否停留在执行完的状态rotateAnimation.setStartOffset(10);//执行前的等待时间xz.setAnimation(rotateAnimation);rotateAnimation.startNow();bd.setOnClickListener(this);zj.setOnClickListener(this);ilike.setOnClickListener(this);likefm.setOnClickListener(this);ytfm.setOnClickListener(this);wd.setOnClickListener(this);

本地音乐

/*** 音乐工具类,扫描系统里面的音频文件,返回一个list集合*/
public class MusicUtils {public static List<Song> getMusicData(Context context) {List<Song> list = new ArrayList<Song>();// 媒体库查询语句(写一个工具类MusicUtils)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 song = new Song();song.song = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));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) {return time / 1000 / 60 + ":0" + time / 1000 % 60;} else {return time / 1000 / 60 + ":" + time / 1000 % 60;}}

播放页面 唱片页面

这里借鉴了https://github.com/AchillesLzg/jianshu-neteasedisc
表示十分的感谢

播放主类

package com.panghaha.it.mymusicplayerdemo.UI;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;import com.panghaha.it.mymusicplayerdemo.R;
import com.panghaha.it.mymusicplayerdemo.model.MusicData2;
import com.panghaha.it.mymusicplayerdemo.service.MusicService;
import com.panghaha.it.mymusicplayerdemo.service.MusicService2;
import com.panghaha.it.mymusicplayerdemo.utils.DisplayUtil;
import com.panghaha.it.mymusicplayerdemo.utils.FastBlurUtil;
import com.panghaha.it.mymusicplayerdemo.widget.BackgourndAnimationRelativeLayout;
import com.panghaha.it.mymusicplayerdemo.widget.DiscView2.IPlayInfo;
import com.panghaha.it.mymusicplayerdemo.widget.DiscView2.MusicChangedStatus;
import com.panghaha.it.mymusicplayerdemo.widget.DiscView2;import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;/**** ━━━━ Code is far away from ━━━━━━*     ()      ()*     ( )    ( )*     ( )    ( )*   ┏┛┻━━━┛┻┓*   ┃   ━   ┃*   ┃ ┳┛ ┗┳ ┃*   ┃   ┻   ┃*   ┗━┓   ┏━┛*     ┃   ┃*     ┃   ┗━━━┓*     ┃       ┣┓*     ┃       ┏┛*     ┗┓┓┏━┳┓┏┛*      ┃┫┫ ┃┫┫*      ┗┻┛ ┗┻┛* ━━━━ bug with the more protecting ━━━* <p/>* Created by PangHaHa12138 on 2017/7/4.*/
public class MusicPlayActivity2 extends AppCompatActivity implements IPlayInfo,View.OnClickListener{private DiscView2 mDisc;private Toolbar mToolbar;private SeekBar mSeekBar;private ImageView mIvPlayOrPause, mIvNext, mIvLast;private TextView mTvMusicDuration,mTvTotalMusicDuration;private BackgourndAnimationRelativeLayout mRootLayout;public static final int MUSIC_MESSAGE = 0;public static final String PARAM_MUSIC_LIST = "PARAM_MUSIC_LIST";private Handler mMusicHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);mSeekBar.setProgress(mSeekBar.getProgress() + 1000);mTvMusicDuration.setText(duration2Time(mSeekBar.getProgress()));startUpdateSeekBarProgress();}};private MusicReceiver mMusicReceiver = new MusicReceiver();private List<MusicData2> mMusicDatas = new ArrayList<>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);setContentView(R.layout.musicplaying2);initMusicDatas();initView();initMusicReceiver();makeStatusBarTransparent();}private void initMusicReceiver() {IntentFilter intentFilter = new IntentFilter();intentFilter.addAction(MusicService.ACTION_STATUS_MUSIC_PLAY);intentFilter.addAction(MusicService.ACTION_STATUS_MUSIC_PAUSE);intentFilter.addAction(MusicService.ACTION_STATUS_MUSIC_DURATION);intentFilter.addAction(MusicService.ACTION_STATUS_MUSIC_COMPLETE);/*注册本地广播*/LocalBroadcastManager.getInstance(this).registerReceiver(mMusicReceiver,intentFilter);}private void initView() {mDisc = (DiscView2) findViewById(R.id.discview);mIvNext = (ImageView) findViewById(R.id.ivNext);mIvLast = (ImageView) findViewById(R.id.ivLast);mIvPlayOrPause = (ImageView) findViewById(R.id.ivPlayOrPause);mTvMusicDuration = (TextView) findViewById(R.id.tvCurrentTime);mTvTotalMusicDuration = (TextView) findViewById(R.id.tvTotalTime);mSeekBar = (SeekBar) findViewById(R.id.musicSeekBar);mRootLayout = (BackgourndAnimationRelativeLayout) findViewById(R.id.rootLayout);mToolbar = (Toolbar) findViewById(R.id.toolBar);setSupportActionBar(mToolbar);mDisc.setPlayInfoListener(this);mIvLast.setOnClickListener(this);mIvNext.setOnClickListener(this);mIvPlayOrPause.setOnClickListener(this);mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {mTvMusicDuration.setText(duration2Time(progress));}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {stopUpdateSeekBarProgree();}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {seekTo(seekBar.getProgress());startUpdateSeekBarProgress();}});mTvMusicDuration.setText(duration2Time(0));mTvTotalMusicDuration.setText(duration2Time(0));mDisc.setMusicDataList(mMusicDatas);}private void stopUpdateSeekBarProgree() {mMusicHandler.removeMessages(MUSIC_MESSAGE);}/*设置透明状态栏*/private void makeStatusBarTransparent() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {Window window = getWindow();window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |View.SYSTEM_UI_FLAG_LAYOUT_STABLE);window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);window.setStatusBarColor(Color.TRANSPARENT);} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);}}String singer;String song;String path;private List<Song> songlist;private void initMusicDatas() {songlist = MusicUtils.getMusicData(this);Intent intentacc = getIntent();path = intentacc.getStringExtra("path");song = intentacc.getStringExtra("song");singer = intentacc.getStringExtra("singer");for (int i = 0; i < songlist.size(); i++) {String p =  songlist.get(i).getPath();String n =  songlist.get(i).getSong();String s =  songlist.get(i).getSinger();mMusicDatas.add(new MusicData2(p,R.drawable.pan1,s,n));}
//        MusicData musicData1 = new MusicData(R.raw.music1, R.raw.ic_music1, "寻", "三亩地");
//        MusicData musicData2 = new MusicData(R.raw.music2, R.raw.ic_music2, "Nightingale", "YANI");
//        MusicData musicData3 = new MusicData(R.raw.music3, R.raw.ic_music3, "Cornfield Chase", "Hans Zimmer");
//        MusicData2 musicData1 = new MusicData2(path,R.drawable.ol54,singer,song);
//        mMusicDatas.clear();
//        mMusicDatas.add(musicData1);
//        mMusicDatas.add(musicData2);
//        mMusicDatas.add(musicData3);//        MusicService musicService = new MusicService();
//        musicService.stop();Intent intent = new Intent(this, MusicService2.class);intent.putExtra(PARAM_MUSIC_LIST, (Serializable) mMusicDatas);startService(intent);}private void try2UpdateMusicPicBackground(final int musicPicRes) {if (mRootLayout.isNeed2UpdateBackground(musicPicRes)) {new Thread(new Runnable() {@Overridepublic void run() {final Drawable foregroundDrawable = getForegroundDrawable(musicPicRes);runOnUiThread(new Runnable() {@Overridepublic void run() {mRootLayout.setForeground(foregroundDrawable);mRootLayout.beginAnimation();}});}}).start();}}private Drawable getForegroundDrawable(int musicPicRes) {/*得到屏幕的宽高比,以便按比例切割图片一部分*/final float widthHeightSize = (float) (DisplayUtil.getScreenWidth(MusicPlayActivity2.this)* 1.0 / DisplayUtil.getScreenHeight(this) * 1.0);Bitmap bitmap = getForegroundBitmap(musicPicRes);int cropBitmapWidth = (int) (widthHeightSize * bitmap.getHeight());int cropBitmapWidthX = (int) ((bitmap.getWidth() - cropBitmapWidth) / 2.0);/*切割部分图片*/Bitmap cropBitmap = Bitmap.createBitmap(bitmap, cropBitmapWidthX, 0, cropBitmapWidth,bitmap.getHeight());/*缩小图片*/Bitmap scaleBitmap = Bitmap.createScaledBitmap(cropBitmap, bitmap.getWidth() / 50, bitmap.getHeight() / 50, false);/*模糊化*/final Bitmap blurBitmap = FastBlurUtil.doBlur(scaleBitmap, 8, true);final Drawable foregroundDrawable = new BitmapDrawable(blurBitmap);/*加入灰色遮罩层,避免图片过亮影响其他控件*/foregroundDrawable.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);return foregroundDrawable;}private Bitmap getForegroundBitmap(int musicPicRes) {int screenWidth = DisplayUtil.getScreenWidth(this);int screenHeight = DisplayUtil.getScreenHeight(this);BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(getResources(), musicPicRes, options);int imageWidth = options.outWidth;int imageHeight = options.outHeight;if (imageWidth < screenWidth && imageHeight < screenHeight) {return BitmapFactory.decodeResource(getResources(), musicPicRes);}int sample = 2;int sampleX = imageWidth / DisplayUtil.getScreenWidth(this);int sampleY = imageHeight / DisplayUtil.getScreenHeight(this);if (sampleX > sampleY && sampleY > 1) {sample = sampleX;} else if (sampleY > sampleX && sampleX > 1) {sample = sampleY;}options.inJustDecodeBounds = false;options.inSampleSize = sample;options.inPreferredConfig = Bitmap.Config.RGB_565;return BitmapFactory.decodeResource(getResources(), musicPicRes, options);}@Overridepublic void onMusicInfoChanged(String musicName, String musicAuthor) {getSupportActionBar().setTitle(musicName);getSupportActionBar().setSubtitle(musicAuthor);}@Overridepublic void onMusicPicChanged(int musicPicRes) {try2UpdateMusicPicBackground(musicPicRes);}@Overridepublic void onMusicChanged(MusicChangedStatus musicChangedStatus) {switch (musicChangedStatus) {case PLAY:{play();break;}case PAUSE:{pause();break;}case NEXT:{next();break;}case LAST:{last();break;}case STOP:{stop();break;}}}@Overridepublic void onClick(View v) {if (v == mIvPlayOrPause) {mDisc.playOrPause();} else if (v == mIvNext) {mDisc.next();} else if (v == mIvLast) {mDisc.last();}}private void play() {optMusic(MusicService.ACTION_OPT_MUSIC_PLAY);startUpdateSeekBarProgress();}private void pause() {optMusic(MusicService.ACTION_OPT_MUSIC_PAUSE);stopUpdateSeekBarProgree();}private void stop() {stopUpdateSeekBarProgree();mIvPlayOrPause.setImageResource(R.drawable.ic_play);mTvMusicDuration.setText(duration2Time(0));mTvTotalMusicDuration.setText(duration2Time(0));mSeekBar.setProgress(0);}private void next() {mRootLayout.postDelayed(new Runnable() {@Overridepublic void run() {optMusic(MusicService.ACTION_OPT_MUSIC_NEXT);}}, 500);stopUpdateSeekBarProgree();mTvMusicDuration.setText(duration2Time(0));mTvTotalMusicDuration.setText(duration2Time(0));}private void last() {mRootLayout.postDelayed(new Runnable() {@Overridepublic void run() {optMusic(MusicService.ACTION_OPT_MUSIC_LAST);}}, 500);stopUpdateSeekBarProgree();mTvMusicDuration.setText(duration2Time(0));mTvTotalMusicDuration.setText(duration2Time(0));}private void complete(boolean isOver) {if (isOver) {mDisc.stop();} else {mDisc.next();}}private void optMusic(final String action) {LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(action));}private void seekTo(int position) {Intent intent = new Intent(MusicService.ACTION_OPT_MUSIC_SEEK_TO);intent.putExtra(MusicService.PARAM_MUSIC_SEEK_TO,position);LocalBroadcastManager.getInstance(this).sendBroadcast(intent);}private void startUpdateSeekBarProgress() {/*避免重复发送Message*/stopUpdateSeekBarProgree();mMusicHandler.sendEmptyMessageDelayed(0,1000);}/*根据时长格式化称时间文本*/private String duration2Time(int duration) {int min = duration / 1000 / 60;int sec = duration / 1000 % 60;return (min < 10 ? "0" + min : min + "") + ":" + (sec < 10 ? "0" + sec : sec + "");}private void updateMusicDurationInfo(int totalDuration) {mSeekBar.setProgress(0);mSeekBar.setMax(totalDuration);mTvTotalMusicDuration.setText(duration2Time(totalDuration));mTvMusicDuration.setText(duration2Time(0));startUpdateSeekBarProgress();}class MusicReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (action.equals(MusicService.ACTION_STATUS_MUSIC_PLAY)) {mIvPlayOrPause.setImageResource(R.drawable.ic_pause);int currentPosition = intent.getIntExtra(MusicService.PARAM_MUSIC_CURRENT_POSITION, 0);mSeekBar.setProgress(currentPosition);if(!mDisc.isPlaying()){mDisc.playOrPause();}} else if (action.equals(MusicService.ACTION_STATUS_MUSIC_PAUSE)) {mIvPlayOrPause.setImageResource(R.drawable.ic_play);if (mDisc.isPlaying()) {mDisc.playOrPause();}} else if (action.equals(MusicService.ACTION_STATUS_MUSIC_DURATION)) {int duration = intent.getIntExtra(MusicService.PARAM_MUSIC_DURATION, 0);updateMusicDurationInfo(duration);} else if (action.equals(MusicService.ACTION_STATUS_MUSIC_COMPLETE)) {boolean isOver = intent.getBooleanExtra(MusicService.PARAM_MUSIC_IS_OVER, true);complete(isOver);}}}@Overrideprotected void onDestroy() {super.onDestroy();LocalBroadcastManager.getInstance(this).unregisterReceiver(mMusicReceiver);}
}

自定义的唱片控件

package com.panghaha.it.mymusicplayerdemo.widget;import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;import com.panghaha.it.mymusicplayerdemo.R;
import com.panghaha.it.mymusicplayerdemo.model.MusicData;
import com.panghaha.it.mymusicplayerdemo.utils.DisplayUtil;import java.util.ArrayList;
import java.util.List;/*** Created by AchillesL on 2016/11/15.*/public class DiscView extends RelativeLayout {private ImageView mIvNeedle;private ViewPager mVpContain;private ViewPagerAdapter mViewPagerAdapter;private ObjectAnimator mNeedleAnimator;private List<View> mDiscLayouts = new ArrayList<>();private List<MusicData> mMusicDatas = new ArrayList<>();private List<ObjectAnimator> mDiscAnimators = new ArrayList<>();/*标记ViewPager是否处于偏移的状态*/private boolean mViewPagerIsOffset = false;/*标记唱针复位后,是否需要重新偏移到唱片处*/private boolean mIsNeed2StartPlayAnimator = false;private MusicStatus musicStatus = MusicStatus.STOP;public static final int DURATION_NEEDLE_ANIAMTOR = 500;private NeedleAnimatorStatus needleAnimatorStatus = NeedleAnimatorStatus.IN_FAR_END;private IPlayInfo mIPlayInfo;private int mScreenWidth, mScreenHeight;/*唱针当前所处的状态*/private enum NeedleAnimatorStatus {/*移动时:从唱盘往远处移动*/TO_FAR_END,/*移动时:从远处往唱盘移动*/TO_NEAR_END,/*静止时:离开唱盘*/IN_FAR_END,/*静止时:贴近唱盘*/IN_NEAR_END}/*音乐当前的状态:只有播放、暂停、停止三种*/public enum MusicStatus {PLAY, PAUSE, STOP}/*DiscView需要触发的音乐切换状态:播放、暂停、上/下一首、停止*/public enum MusicChangedStatus {PLAY, PAUSE, NEXT, LAST, STOP}public interface IPlayInfo {/*用于更新标题栏变化*/public void onMusicInfoChanged(String musicName, String musicAuthor);/*用于更新背景图片*/public void onMusicPicChanged(int musicPicRes);/*用于更新音乐播放状态*/public void onMusicChanged(MusicChangedStatus musicChangedStatus);}public DiscView(Context context) {this(context, null);}public DiscView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public DiscView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mScreenWidth = DisplayUtil.getScreenWidth(context);mScreenHeight = DisplayUtil.getScreenHeight(context);}@Overrideprotected void onFinishInflate() {super.onFinishInflate();initDiscBlackground();initViewPager();initNeedle();initObjectAnimator();}private void initDiscBlackground() {ImageView mDiscBlackground = (ImageView) findViewById(R.id.ivDiscBlackgound);mDiscBlackground.setImageDrawable(getDiscBlackgroundDrawable());int marginTop = (int) (DisplayUtil.SCALE_DISC_MARGIN_TOP * mScreenHeight);LayoutParams layoutParams = (LayoutParams) mDiscBlackground.getLayoutParams();layoutParams.setMargins(0, marginTop, 0, 0);mDiscBlackground.setLayoutParams(layoutParams);}private void initViewPager() {mViewPagerAdapter = new ViewPagerAdapter();mVpContain = (ViewPager) findViewById(R.id.vpDiscContain);mVpContain.setOverScrollMode(View.OVER_SCROLL_NEVER);mVpContain.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {int lastPositionOffsetPixels = 0;int currentItem = 0;@Overridepublic void onPageScrolled(int position, float positionOffset, intpositionOffsetPixels) {//左滑if (lastPositionOffsetPixels > positionOffsetPixels) {if (positionOffset < 0.5) {notifyMusicInfoChanged(position);} else {notifyMusicInfoChanged(mVpContain.getCurrentItem());}}//右滑else if (lastPositionOffsetPixels < positionOffsetPixels) {if (positionOffset > 0.5) {notifyMusicInfoChanged(position + 1);} else {notifyMusicInfoChanged(position);}}lastPositionOffsetPixels = positionOffsetPixels;}@Overridepublic void onPageSelected(int position) {resetOtherDiscAnimation(position);notifyMusicPicChanged(position);if (position > currentItem) {notifyMusicStatusChanged(MusicChangedStatus.NEXT);} else {notifyMusicStatusChanged(MusicChangedStatus.LAST);}currentItem = position;}@Overridepublic void onPageScrollStateChanged(int state) {doWithAnimatorOnPageScroll(state);}});mVpContain.setAdapter(mViewPagerAdapter);LayoutParams layoutParams = (LayoutParams) mVpContain.getLayoutParams();int marginTop = (int) (DisplayUtil.SCALE_DISC_MARGIN_TOP * mScreenHeight);layoutParams.setMargins(0, marginTop, 0, 0);mVpContain.setLayoutParams(layoutParams);}/*** 取消其他页面上的动画,并将图片旋转角度复原*/private void resetOtherDiscAnimation(int position) {for (int i = 0; i < mDiscLayouts.size(); i++) {if (position == i) continue;mDiscAnimators.get(position).cancel();ImageView imageView = (ImageView) mDiscLayouts.get(i).findViewById(R.id.ivDisc);imageView.setRotation(0);}}private void doWithAnimatorOnPageScroll(int state) {switch (state) {case ViewPager.SCROLL_STATE_IDLE:case ViewPager.SCROLL_STATE_SETTLING: {mViewPagerIsOffset = false;if (musicStatus == MusicStatus.PLAY) {playAnimator();}break;}case ViewPager.SCROLL_STATE_DRAGGING: {mViewPagerIsOffset = true;pauseAnimator();break;}}}private void initNeedle() {mIvNeedle = (ImageView) findViewById(R.id.ivNeedle);int needleWidth = (int) (DisplayUtil.SCALE_NEEDLE_WIDTH * mScreenWidth);int needleHeight = (int) (DisplayUtil.SCALE_NEEDLE_HEIGHT * mScreenHeight);/*设置手柄的外边距为负数,让其隐藏一部分*/int marginTop = (int) (DisplayUtil.SCALE_NEEDLE_MARGIN_TOP * mScreenHeight) * -1;int marginLeft = (int) (DisplayUtil.SCALE_NEEDLE_MARGIN_LEFT * mScreenWidth);Bitmap originBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_needle);Bitmap bitmap = Bitmap.createScaledBitmap(originBitmap, needleWidth, needleHeight, false);LayoutParams layoutParams = (LayoutParams) mIvNeedle.getLayoutParams();layoutParams.setMargins(marginLeft, marginTop, 0, 0);int pivotX = (int) (DisplayUtil.SCALE_NEEDLE_PIVOT_X * mScreenWidth);int pivotY = (int) (DisplayUtil.SCALE_NEEDLE_PIVOT_Y * mScreenWidth);mIvNeedle.setPivotX(pivotX);mIvNeedle.setPivotY(pivotY);mIvNeedle.setRotation(DisplayUtil.ROTATION_INIT_NEEDLE);mIvNeedle.setImageBitmap(bitmap);mIvNeedle.setLayoutParams(layoutParams);}private void initObjectAnimator() {mNeedleAnimator = ObjectAnimator.ofFloat(mIvNeedle, View.ROTATION, DisplayUtil.ROTATION_INIT_NEEDLE, 0);mNeedleAnimator.setDuration(DURATION_NEEDLE_ANIAMTOR);mNeedleAnimator.setInterpolator(new AccelerateInterpolator());mNeedleAnimator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animator) {/*** 根据动画开始前NeedleAnimatorStatus的状态,* 即可得出动画进行时NeedleAnimatorStatus的状态* */if (needleAnimatorStatus == NeedleAnimatorStatus.IN_FAR_END) {needleAnimatorStatus = NeedleAnimatorStatus.TO_NEAR_END;} else if (needleAnimatorStatus == NeedleAnimatorStatus.IN_NEAR_END) {needleAnimatorStatus = NeedleAnimatorStatus.TO_FAR_END;}}@Overridepublic void onAnimationEnd(Animator animator) {if (needleAnimatorStatus == NeedleAnimatorStatus.TO_NEAR_END) {needleAnimatorStatus = NeedleAnimatorStatus.IN_NEAR_END;int index = mVpContain.getCurrentItem();playDiscAnimator(index);musicStatus = MusicStatus.PLAY;} else if (needleAnimatorStatus == NeedleAnimatorStatus.TO_FAR_END) {needleAnimatorStatus = NeedleAnimatorStatus.IN_FAR_END;if (musicStatus == MusicStatus.STOP) {mIsNeed2StartPlayAnimator = true;}}if (mIsNeed2StartPlayAnimator) {mIsNeed2StartPlayAnimator = false;/*** 只有在ViewPager不处于偏移状态时,才开始唱盘旋转动画* */if (!mViewPagerIsOffset) {/*延时500ms*/DiscView.this.postDelayed(new Runnable() {@Overridepublic void run() {playAnimator();}}, 50);}}}@Overridepublic void onAnimationCancel(Animator animator) {}@Overridepublic void onAnimationRepeat(Animator animator) {}});}public void setPlayInfoListener(IPlayInfo listener) {this.mIPlayInfo = listener;}/*得到唱盘背后半透明的圆形背景*/private Drawable getDiscBlackgroundDrawable() {int discSize = (int) (mScreenWidth * DisplayUtil.SCALE_DISC_SIZE);Bitmap bitmapDisc = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_disc_blackground), discSize, discSize, false);RoundedBitmapDrawable roundDiscDrawable = RoundedBitmapDrawableFactory.create(getResources(), bitmapDisc);return roundDiscDrawable;}/*** 得到唱盘图片* 唱盘图片由空心圆盘及音乐专辑图片“合成”得到*/private Drawable getDiscDrawable(int musicPicRes) {int discSize = (int) (mScreenWidth * DisplayUtil.SCALE_DISC_SIZE);int musicPicSize = (int) (mScreenWidth * DisplayUtil.SCALE_MUSIC_PIC_SIZE);Bitmap bitmapDisc = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_disc), discSize, discSize, false);Bitmap bitmapMusicPic = getMusicPicBitmap(musicPicSize,musicPicRes);BitmapDrawable discDrawable = new BitmapDrawable(bitmapDisc);RoundedBitmapDrawable roundMusicDrawable = RoundedBitmapDrawableFactory.create(getResources(), bitmapMusicPic);//抗锯齿discDrawable.setAntiAlias(true);roundMusicDrawable.setAntiAlias(true);Drawable[] drawables = new Drawable[2];drawables[0] = roundMusicDrawable;drawables[1] = discDrawable;LayerDrawable layerDrawable = new LayerDrawable(drawables);int musicPicMargin = (int) ((DisplayUtil.SCALE_DISC_SIZE - DisplayUtil.SCALE_MUSIC_PIC_SIZE) * mScreenWidth / 2);//调整专辑图片的四周边距,让其显示在正中layerDrawable.setLayerInset(0, musicPicMargin, musicPicMargin, musicPicMargin,musicPicMargin);return layerDrawable;}private Bitmap getMusicPicBitmap(int musicPicSize, int musicPicRes) {BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(getResources(),musicPicRes,options);int imageWidth = options.outWidth;int sample = imageWidth / musicPicSize;int dstSample = 1;if (sample > dstSample) {dstSample = sample;}options.inJustDecodeBounds = false;//设置图片采样率options.inSampleSize = dstSample;//设置图片解码格式options.inPreferredConfig = Bitmap.Config.RGB_565;return Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(),musicPicRes, options), musicPicSize, musicPicSize, true);}public void setMusicDataList(List<MusicData> musicDataList) {if (musicDataList.isEmpty()) return;mDiscLayouts.clear();mMusicDatas.clear();mDiscAnimators.clear();mMusicDatas.addAll(musicDataList);int i = 0;for (MusicData musicData : mMusicDatas) {View discLayout = LayoutInflater.from(getContext()).inflate(R.layout.layout_disc,mVpContain, false);ImageView disc = (ImageView) discLayout.findViewById(R.id.ivDisc);disc.setImageDrawable(getDiscDrawable(musicData.getMusicPicRes()));mDiscAnimators.add(getDiscObjectAnimator(disc, i++));mDiscLayouts.add(discLayout);}mViewPagerAdapter.notifyDataSetChanged();MusicData musicData = mMusicDatas.get(0);if (mIPlayInfo != null) {mIPlayInfo.onMusicInfoChanged(musicData.getMusicName(), musicData.getMusicAuthor());mIPlayInfo.onMusicPicChanged(musicData.getMusicPicRes());}}private ObjectAnimator getDiscObjectAnimator(ImageView disc, final int i) {ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(disc, View.ROTATION, 0, 360);objectAnimator.setRepeatCount(ValueAnimator.INFINITE);objectAnimator.setDuration(20 * 1000);objectAnimator.setInterpolator(new LinearInterpolator());return objectAnimator;}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();}/*播放动画*/private void playAnimator() {/*唱针处于远端时,直接播放动画*/if (needleAnimatorStatus == NeedleAnimatorStatus.IN_FAR_END) {mNeedleAnimator.start();}/*唱针处于往远端移动时,设置标记,等动画结束后再播放动画*/else if (needleAnimatorStatus == NeedleAnimatorStatus.TO_FAR_END) {mIsNeed2StartPlayAnimator = true;}}/*暂停动画*/private void pauseAnimator() {/*播放时暂停动画*/if (needleAnimatorStatus == NeedleAnimatorStatus.IN_NEAR_END) {int index = mVpContain.getCurrentItem();pauseDiscAnimatior(index);}/*唱针往唱盘移动时暂停动画*/else if (needleAnimatorStatus == NeedleAnimatorStatus.TO_NEAR_END) {mNeedleAnimator.reverse();/*** 若动画在没结束时执行reverse方法,则不会执行监听器的onStart方法,此时需要手动设置* */needleAnimatorStatus = NeedleAnimatorStatus.TO_FAR_END;}/*** 动画可能执行多次,只有音乐处于停止 / 暂停状态时,才执行暂停命令* */if (musicStatus == MusicStatus.STOP) {notifyMusicStatusChanged(MusicChangedStatus.STOP);}else if (musicStatus == MusicStatus.PAUSE) {notifyMusicStatusChanged(MusicChangedStatus.PAUSE);}}/*播放唱盘动画*/private void playDiscAnimator(int index) {ObjectAnimator objectAnimator = mDiscAnimators.get(index);if (objectAnimator.isPaused()) {objectAnimator.resume();} else {objectAnimator.start();}/*** 唱盘动画可能执行多次,只有不是音乐不在播放状态,在回调执行播放* */if (musicStatus != MusicStatus.PLAY) {notifyMusicStatusChanged(MusicChangedStatus.PLAY);}}/*暂停唱盘动画*/private void pauseDiscAnimatior(int index) {ObjectAnimator objectAnimator = mDiscAnimators.get(index);objectAnimator.pause();mNeedleAnimator.reverse();}public void notifyMusicInfoChanged(int position) {if (mIPlayInfo != null) {MusicData musicData = mMusicDatas.get(position);mIPlayInfo.onMusicInfoChanged(musicData.getMusicName(), musicData.getMusicAuthor());}}public void notifyMusicPicChanged(int position) {if (mIPlayInfo != null) {MusicData musicData = mMusicDatas.get(position);mIPlayInfo.onMusicPicChanged(musicData.getMusicPicRes());}}public void notifyMusicStatusChanged(MusicChangedStatus musicChangedStatus) {if (mIPlayInfo != null) {mIPlayInfo.onMusicChanged(musicChangedStatus);}}private void play() {playAnimator();}private void pause() {musicStatus = MusicStatus.PAUSE;pauseAnimator();}public void stop() {musicStatus = MusicStatus.STOP;pauseAnimator();}public void playOrPause() {if (musicStatus == MusicStatus.PLAY) {pause();} else {play();}}public void next() {int currentItem = mVpContain.getCurrentItem();if (currentItem == mMusicDatas.size() - 1) {Toast.makeText(getContext(), "已经到达最后一首", Toast.LENGTH_SHORT).show();} else {selectMusicWithButton();mVpContain.setCurrentItem(currentItem + 1, true);}}public void last() {int currentItem = mVpContain.getCurrentItem();if (currentItem == 0) {Toast.makeText(getContext(), "已经到达第一首", Toast.LENGTH_SHORT).show();} else {selectMusicWithButton();mVpContain.setCurrentItem(currentItem - 1, true);}}public boolean isPlaying() {return musicStatus == MusicStatus.PLAY;}private void selectMusicWithButton() {if (musicStatus == MusicStatus.PLAY) {mIsNeed2StartPlayAnimator = true;pauseAnimator();} else if (musicStatus == MusicStatus.PAUSE) {play();}}class ViewPagerAdapter extends PagerAdapter {@Overridepublic Object instantiateItem(ViewGroup container, int position) {View discLayout = mDiscLayouts.get(position);container.addView(discLayout);return discLayout;}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {container.removeView(mDiscLayouts.get(position));}@Overridepublic int getCount() {return mDiscLayouts.size();}@Overridepublic boolean isViewFromObject(View view, Object object) {return view == object;}}
}

开启服务播放音乐

package com.panghaha.it.mymusicplayerdemo.service;import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;import com.panghaha.it.mymusicplayerdemo.UI.MusicPlayActivity;
import com.panghaha.it.mymusicplayerdemo.model.MusicData;import java.util.ArrayList;
import java.util.List;/*** Created by AchillesL on 2016/11/18.*/public class MusicService extends Service implements MediaPlayer.OnCompletionListener {/*操作指令*/public static final String ACTION_OPT_MUSIC_PLAY = "ACTION_OPT_MUSIC_PLAY";public static final String ACTION_OPT_MUSIC_PAUSE = "ACTION_OPT_MUSIC_PAUSE";public static final String ACTION_OPT_MUSIC_NEXT = "ACTION_OPT_MUSIC_NEXT";public static final String ACTION_OPT_MUSIC_LAST = "ACTION_OPT_MUSIC_LAST";public static final String ACTION_OPT_MUSIC_SEEK_TO = "ACTION_OPT_MUSIC_SEEK_TO";/*状态指令*/public static final String ACTION_STATUS_MUSIC_PLAY = "ACTION_STATUS_MUSIC_PLAY";public static final String ACTION_STATUS_MUSIC_PAUSE = "ACTION_STATUS_MUSIC_PAUSE";public static final String ACTION_STATUS_MUSIC_COMPLETE = "ACTION_STATUS_MUSIC_COMPLETE";public static final String ACTION_STATUS_MUSIC_DURATION = "ACTION_STATUS_MUSIC_DURATION";public static final String PARAM_MUSIC_DURATION = "PARAM_MUSIC_DURATION";public static final String PARAM_MUSIC_SEEK_TO = "PARAM_MUSIC_SEEK_TO";public static final String PARAM_MUSIC_CURRENT_POSITION = "PARAM_MUSIC_CURRENT_POSITION";public static final String PARAM_MUSIC_IS_OVER = "PARAM_MUSIC_IS_OVER";private int mCurrentMusicIndex = 0;private boolean mIsMusicPause = false;private List<MusicData> mMusicDatas = new ArrayList<>();private MusicReceiver mMusicReceiver = new MusicReceiver();private MediaPlayer mMediaPlayer = new MediaPlayer();@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {initMusicDatas(intent);return super.onStartCommand(intent, flags, startId);}@Overridepublic void onCreate() {super.onCreate();initBoardCastReceiver();}private void initMusicDatas(Intent intent) {if (intent == null) return;List<MusicData> musicDatas =(List<MusicData>) intent.getSerializableExtra(MusicPlayActivity.PARAM_MUSIC_LIST);mMusicDatas.addAll(musicDatas);}private void initBoardCastReceiver() {IntentFilter intentFilter = new IntentFilter();intentFilter.addAction(ACTION_OPT_MUSIC_PLAY);intentFilter.addAction(ACTION_OPT_MUSIC_PAUSE);intentFilter.addAction(ACTION_OPT_MUSIC_NEXT);intentFilter.addAction(ACTION_OPT_MUSIC_LAST);intentFilter.addAction(ACTION_OPT_MUSIC_SEEK_TO);LocalBroadcastManager.getInstance(this).registerReceiver(mMusicReceiver,intentFilter);}@Overridepublic void onDestroy() {super.onDestroy();mMediaPlayer.release();mMediaPlayer = null;LocalBroadcastManager.getInstance(this).unregisterReceiver(mMusicReceiver);}private void play(final int index) {if (index >= mMusicDatas.size()) return;if (mCurrentMusicIndex == index && mIsMusicPause) {mMediaPlayer.start();} else {mMediaPlayer.stop();mMediaPlayer = null;mMediaPlayer = MediaPlayer.create(getApplicationContext(), mMusicDatas.get(index).getMusicRes());mMediaPlayer.start();mMediaPlayer.setOnCompletionListener(this);mCurrentMusicIndex = index;mIsMusicPause = false;int duration = mMediaPlayer.getDuration();sendMusicDurationBroadCast(duration);}sendMusicStatusBroadCast(ACTION_STATUS_MUSIC_PLAY);}private void pause() {mMediaPlayer.pause();mIsMusicPause = true;sendMusicStatusBroadCast(ACTION_STATUS_MUSIC_PAUSE);}public void stop() {mMediaPlayer.stop();}private void next() {if (mCurrentMusicIndex + 1 < mMusicDatas.size()) {play(mCurrentMusicIndex + 1);} else {stop();}}private void last() {if (mCurrentMusicIndex != 0) {play(mCurrentMusicIndex - 1);}}private void seekTo(Intent intent) {if (mMediaPlayer.isPlaying()) {int position = intent.getIntExtra(PARAM_MUSIC_SEEK_TO, 0);mMediaPlayer.seekTo(position);}}@Overridepublic void onCompletion(MediaPlayer mp) {sendMusicCompleteBroadCast();}class MusicReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (action.equals(ACTION_OPT_MUSIC_PLAY)) {play(mCurrentMusicIndex);} else if (action.equals(ACTION_OPT_MUSIC_PAUSE)) {pause();} else if (action.equals(ACTION_OPT_MUSIC_LAST)) {last();} else if (action.equals(ACTION_OPT_MUSIC_NEXT)) {next();} else if (action.equals(ACTION_OPT_MUSIC_SEEK_TO)) {seekTo(intent);}}}private void sendMusicCompleteBroadCast() {Intent intent = new Intent(ACTION_STATUS_MUSIC_COMPLETE);intent.putExtra(PARAM_MUSIC_IS_OVER, (mCurrentMusicIndex == mMusicDatas.size() - 1));LocalBroadcastManager.getInstance(this).sendBroadcast(intent);}private void sendMusicDurationBroadCast(int duration) {Intent intent = new Intent(ACTION_STATUS_MUSIC_DURATION);intent.putExtra(PARAM_MUSIC_DURATION, duration);LocalBroadcastManager.getInstance(this).sendBroadcast(intent);}private void sendMusicStatusBroadCast(String action) {Intent intent = new Intent(action);if (action.equals(ACTION_STATUS_MUSIC_PLAY)) {intent.putExtra(PARAM_MUSIC_CURRENT_POSITION,mMediaPlayer.getCurrentPosition());}LocalBroadcastManager.getInstance(this).sendBroadcast(intent);}}

这里是本地广播配合seekbar进度监听完成的拖动seekbar改变播放进度

  private void sendMusicCompleteBroadCast() {Intent intent = new Intent(ACTION_STATUS_MUSIC_COMPLETE);intent.putExtra(PARAM_MUSIC_IS_OVER, (mCurrentMusicIndex == mMusicDatas.size() - 1));LocalBroadcastManager.getInstance(this).sendBroadcast(intent);}private void sendMusicDurationBroadCast(int duration) {Intent intent = new Intent(ACTION_STATUS_MUSIC_DURATION);intent.putExtra(PARAM_MUSIC_DURATION, duration);LocalBroadcastManager.getInstance(this).sendBroadcast(intent);}private void sendMusicStatusBroadCast(String action) {Intent intent = new Intent(action);if (action.equals(ACTION_STATUS_MUSIC_PLAY)) {intent.putExtra(PARAM_MUSIC_CURRENT_POSITION,mMediaPlayer.getCurrentPosition());}LocalBroadcastManager.getInstance(this).sendBroadcast(intent);}

高仿网易云音乐一(可扫描本地音乐播放)相关推荐

  1. Vue3.0 + typescript 高仿网易云音乐 WebApp

    Vue3.0 + typescript 高仿网易云音乐 WebApp 前言 Vue3.0 的正式发布,让我心动不已,于是尝试用 vue3 实现一个完整的项目,整个项目全部使用了 composition ...

  2. android 仿网易标签切换,高仿网易云音乐客户端的Home页面切换Tabhost-IT蓝豹

    1.高仿网易云音乐客户端的Home页面切换Tabhost 高仿网易云音乐客户端的Home页面切换Tabhost,并且三角形是透明的, 实现方式,自定义AnimTabsView继承 RelativeLa ...

  3. Flutter+FishRedux高仿网易云音乐

    flutter_netease_cloud_music 采用FishRedux框架与开源网易云音乐api开发的高仿网易云音乐APP,技术栈主要是:Flutter+FishRedux,目前主要是偏重AP ...

  4. 高仿网易云音乐(vue实战项目)

    高仿网易云音乐(Vue实战项目)

  5. 新鲜出炉高仿网易云音乐 APP

    我的引语 晚上好,我是吴小龙同学,我的公众号「菜鸟翻身」会推荐 GitHub 上好玩的项目,一分钟 get 一个优秀的开源项目,挖掘开源的价值,欢迎关注我. 项目中成长是最快的,如何成长,就是解决问题 ...

  6. 基于vue的高仿网易云音乐网站,实现大多数功能

    文章目录 前言 项目演示地址 线上地址 项目仓库 总结 前言 基于Vue + Vue-Router + Vuex + axios + elementui,ui参考网易云音乐,后端接口使用网易云音乐接口 ...

  7. 有没有java自编歌曲,高仿网易云音乐一(可扫描本地音乐播放)

    最近闲下来做了个仿网易云音乐的音乐播放器 效果图: p1.png p2.png p3.png p4.png p5.png p6.png 项目下载地址 闪屏 1.gif 扫描本地音乐 3.gif 播放 ...

  8. 高仿网易云音乐UI的微信小程序源码

    简介: 仿网易云音乐的微信小程序源码,名为YY音乐小程序,首页有每日推荐歌曲.歌单和热歌排行榜,功能不是特别多但是该有的都有. UI特别精致,简直就是克隆的网易云音乐. 源码下载:百度网盘自取 图片:

  9. Android高仿网易云音乐OkHttp+Retrofit+RxJava+Glide+MVC+MVVM

    简介 这是一个使用Java(以后还会推出Kotlin版本)语言,从0开发一个Android平台,接近企业级的项目(我的云音乐),包含了基础内容,高级内容,项目封装,项目重构等知识:主要是使用系统功能, ...

最新文章

  1. 安装.Net Framework 4.6.2时出现“无法建立到信任根颁发机构的证书链”解决方法
  2. 突发,Log4j2 爆出远程代码执行漏洞,各大厂纷纷中招!
  3. Python 调用C函数
  4. OpenStack_I版 1.准备过程
  5. [你必须知道的.NET] 第三回:历史纠葛:特性和属性
  6. 玩转Koa之核心原理分析
  7. win11资源管理器卡顿怎么办 Windows11解决资源管理器卡顿的步骤方法
  8. 算法笔记-------快速排序
  9. java 反解析cron_Cron表达式解析
  10. 使用阿里的【字体图标】期望的效果
  11. The road to learning English-Grammar
  12. 纳尼?华为首席架构师只用434页笔记,就将网络协议给拿下了
  13. APP开发定制需求的常说分销模式,对于分销大家了解多少呢?
  14. 买服务器不做网站需要备案吗,买服务器需要备案吗
  15. Excel简单函数运用
  16. 【转】NAS群晖DSM 5.0-4458安装教程
  17. 外贸人常用的几种客户开发渠道
  18. Android 9 行为变更:所有应用
  19. 珊瑚SDK多人游戏对战的系统支持!
  20. 索尼常务董事:绩效主义毁了索尼

热门文章

  1. Linux部署springboot项目(从安装java开始)
  2. 【51单片机】考试例程|汇编实现
  3. 名片管理系统java_java毕业设计_springboot框架的名片管理系统
  4. 春秋旅游移动app设计界面
  5. 软件测试工程师笔试题
  6. DEV、SIT、UAT、PET、SIM、PRD、PROD缩写介绍
  7. 两个进程共享内存,一个写,一个读
  8. 中国各类医院排行(仅供参考)
  9. how to search books in gitbook
  10. 把握出租车行驶的数据脉搏 :出租车轨迹数据给你答案!