清单文件添加

 <service
            android:name="com.rookie.shiyue20180528.model.MusicService"android:enabled="true"android:exported="false"/>

style.xml

<!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"><!-- Customize your theme here. --><item name="colorPrimary">@color/colorPrimary</item><item name="colorPrimaryDark">@color/colorPrimaryDark</item><item name="colorAccent">@android:color/holo_red_light</item><item name="windowNoTitle">true</item><item name="android:windowTranslucentStatus" tools:ignore="NewApi">true</item></style><style name="netease_toolbar_title" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"><item name="android:textColor">@android:color/white</item><item name="android:textSize">17sp</item></style><style name="netease_toolbar_subtitle" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Subtitle"><item name="android:textColor">#eeeeee</item><item name="android:textSize">14sp</item></style><style name="neteasa_music_time_text_sytle"><item name="android:layout_width">wrap_content</item><item name="android:layout_height">wrap_content</item><item name="android:textColor">#ccc</item><item name="android:textSize">9sp</item></style><style name="neteasa_music_time_seek_bar_sytle"parent="Widget.AppCompat.SeekBar"><item name="android:layout_width">match_parent</item><item name="android:layout_height">wrap_content</item><item name="android:thumb">@drawable/ic_seekbar_thumb</item></style>

MainActivity

public class MainActivity extends AppCompatActivity implements DiscView.IPlayInfo, View.OnClickListener {private DiscView 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<MusicData> mMusicDatas = new ArrayList<>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);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 = (DiscView) 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);}}private void initMusicDatas() {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");mMusicDatas.add(musicData1);mMusicDatas.add(musicData2);mMusicDatas.add(musicData3);Intent intent = new Intent(this, MusicService.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(MainActivity.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(DiscView.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);}},1000);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);}}, 1000);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);}
}

FastBlurUtil

public class FastBlurUtil {public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {Bitmap bitmap;if (canReuseInBitmap) {bitmap = sentBitmap;} else {bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);}if (radius < 1) {return (null);}int w = bitmap.getWidth();int h = bitmap.getHeight();int[] pix = new int[w * h];bitmap.getPixels(pix, 0, w, 0, 0, w, h);int wm = w - 1;int hm = h - 1;int wh = w * h;int div = radius + radius + 1;int r[] = new int[wh];int g[] = new int[wh];int b[] = new int[wh];int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;int vmin[] = new int[Math.max(w, h)];int divsum = (div + 1) >> 1;divsum *= divsum;int dv[] = new int[256 * divsum];for (i = 0; i < 256 * divsum; i++) {dv[i] = (i / divsum);}yw = yi = 0;int[][] stack = new int[div][3];int stackpointer;int stackstart;int[] sir;int rbs;int r1 = radius + 1;int routsum, goutsum, boutsum;int rinsum, ginsum, binsum;for (y = 0; y < h; y++) {rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;for (i = -radius; i <= radius; i++) {p = pix[yi + Math.min(wm, Math.max(i, 0))];sir = stack[i + radius];sir[0] = (p & 0xff0000) >> 16;sir[1] = (p & 0x00ff00) >> 8;sir[2] = (p & 0x0000ff);rbs = r1 - Math.abs(i);rsum += sir[0] * rbs;gsum += sir[1] * rbs;bsum += sir[2] * rbs;if (i > 0) {rinsum += sir[0];ginsum += sir[1];binsum += sir[2];} else {routsum += sir[0];goutsum += sir[1];boutsum += sir[2];}}stackpointer = radius;for (x = 0; x < w; x++) {r[yi] = dv[rsum];g[yi] = dv[gsum];b[yi] = dv[bsum];rsum -= routsum;gsum -= goutsum;bsum -= boutsum;stackstart = stackpointer - radius + div;sir = stack[stackstart % div];routsum -= sir[0];goutsum -= sir[1];boutsum -= sir[2];if (y == 0) {vmin[x] = Math.min(x + radius + 1, wm);}p = pix[yw + vmin[x]];sir[0] = (p & 0xff0000) >> 16;sir[1] = (p & 0x00ff00) >> 8;sir[2] = (p & 0x0000ff);rinsum += sir[0];ginsum += sir[1];binsum += sir[2];rsum += rinsum;gsum += ginsum;bsum += binsum;stackpointer = (stackpointer + 1) % div;sir = stack[(stackpointer) % div];routsum += sir[0];goutsum += sir[1];boutsum += sir[2];rinsum -= sir[0];ginsum -= sir[1];binsum -= sir[2];yi++;}yw += w;}for (x = 0; x < w; x++) {rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;yp = -radius * w;for (i = -radius; i <= radius; i++) {yi = Math.max(0, yp) + x;sir = stack[i + radius];sir[0] = r[yi];sir[1] = g[yi];sir[2] = b[yi];rbs = r1 - Math.abs(i);rsum += r[yi] * rbs;gsum += g[yi] * rbs;bsum += b[yi] * rbs;if (i > 0) {rinsum += sir[0];ginsum += sir[1];binsum += sir[2];} else {routsum += sir[0];goutsum += sir[1];boutsum += sir[2];}if (i < hm) {yp += w;}}yi = x;stackpointer = radius;for (y = 0; y < h; y++) {// Preserve alpha channel: ( 0xff000000 & pix[yi] )pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];rsum -= routsum;gsum -= goutsum;bsum -= boutsum;stackstart = stackpointer - radius + div;sir = stack[stackstart % div];routsum -= sir[0];goutsum -= sir[1];boutsum -= sir[2];if (x == 0) {vmin[y] = Math.min(y + r1, hm) * w;}p = x + vmin[y];sir[0] = r[p];sir[1] = g[p];sir[2] = b[p];rinsum += sir[0];ginsum += sir[1];binsum += sir[2];rsum += rinsum;gsum += ginsum;bsum += binsum;stackpointer = (stackpointer + 1) % div;sir = stack[stackpointer];routsum += sir[0];goutsum += sir[1];boutsum += sir[2];rinsum -= sir[0];ginsum -= sir[1];binsum -= sir[2];yi += w;}}bitmap.setPixels(pix, 0, w, 0, 0, w, h);return (bitmap);}}

DisplayUtil

public class DisplayUtil {/*手柄起始角度*/public static final float ROTATION_INIT_NEEDLE = -30;/*截图屏幕宽高*/private static final float BASE_SCREEN_WIDTH = (float) 1080.0;private static final float BASE_SCREEN_HEIGHT = (float) 1920.0;/*唱针宽高、距离等比例*/public static final float SCALE_NEEDLE_WIDTH = (float) (276.0 / BASE_SCREEN_WIDTH);public static final float SCALE_NEEDLE_MARGIN_LEFT = (float) (500.0 / BASE_SCREEN_WIDTH);public static final float SCALE_NEEDLE_PIVOT_X = (float) (43.0 / BASE_SCREEN_WIDTH);public static final float SCALE_NEEDLE_PIVOT_Y = (float) (43.0 / BASE_SCREEN_WIDTH);public static final float SCALE_NEEDLE_HEIGHT = (float) (413.0 / BASE_SCREEN_HEIGHT);public static final float SCALE_NEEDLE_MARGIN_TOP = (float) (43.0 / BASE_SCREEN_HEIGHT);/*唱盘比例*/public static final float SCALE_DISC_SIZE = (float) (813.0 / BASE_SCREEN_WIDTH);public static final float SCALE_DISC_MARGIN_TOP = (float) (190 / BASE_SCREEN_HEIGHT);/*专辑图片比例*/public static final float SCALE_MUSIC_PIC_SIZE = (float) (533.0 / BASE_SCREEN_WIDTH);/*设备屏幕宽度*/public static int getScreenWidth(Context context) {return context.getResources().getDisplayMetrics().widthPixels;}/*设备屏幕高度*/public static int getScreenHeight(Context context) {return context.getResources().getDisplayMetrics().heightPixels;}
}

MusicService

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(MainActivity.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);}private 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);}}

MusicData

public class MusicData implements Serializable {/*音乐资源id*/private int mMusicRes;/*专辑图片id*/private int mMusicPicRes;/*音乐名称*/private String mMusicName;/*作者*/private String mMusicAuthor;public MusicData(int mMusicRes, int mMusicPicRes, String mMusicName, String mMusicAuthor) {this.mMusicRes = mMusicRes;this.mMusicPicRes = mMusicPicRes;this.mMusicName = mMusicName;this.mMusicAuthor = mMusicAuthor;}public int getMusicRes() {return mMusicRes;}public int getMusicPicRes() {return mMusicPicRes;}public String getMusicName() {return mMusicName;}public String getMusicAuthor() {return mMusicAuthor;}
}

DiscView

import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
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.rookie.shiyue20180528.R;
import com.rookie.shiyue20180528.utils.DisplayUtil;import java.util.ArrayList;
import java.util.List;/*** Created by 暗夜 on 2018/5/28.*//*** 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);RelativeLayout.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);RelativeLayout.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);RelativeLayout.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;}}
}

BackgourndAnimationRelativeLayout

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.animation.AccelerateInterpolator;
import android.widget.RelativeLayout;import com.rookie.shiyue20180528.R;/*** Created by 暗夜 on 2018/5/28.*/public class BackgourndAnimationRelativeLayout extends RelativeLayout {private final int DURATION_ANIMATION = 500;private final int INDEX_BACKGROUND = 0;private final int INDEX_FOREGROUND = 1;/*** LayerDrawable[0]: background drawable* LayerDrawable[1]: foreground drawable*/private LayerDrawable layerDrawable;private ObjectAnimator objectAnimator;private int musicPicRes = -1;public BackgourndAnimationRelativeLayout(Context context) {this(context, null);}public BackgourndAnimationRelativeLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public BackgourndAnimationRelativeLayout(Context context, AttributeSet attrs, intdefStyleAttr) {super(context, attrs, defStyleAttr);initLayerDrawable();initObjectAnimator();}@TargetApi(Build.VERSION_CODES.LOLLIPOP)private void initLayerDrawable() {Drawable backgroundDrawable = getContext().getDrawable(R.drawable.ic_blackground);Drawable[] drawables = new Drawable[2];/*初始化时先将前景与背景颜色设为一致*/drawables[INDEX_BACKGROUND] = backgroundDrawable;drawables[INDEX_FOREGROUND] = backgroundDrawable;layerDrawable = new LayerDrawable(drawables);}private void initObjectAnimator() {objectAnimator = ObjectAnimator.ofFloat(this, "number", 0f, 1.0f);objectAnimator.setDuration(DURATION_ANIMATION);objectAnimator.setInterpolator(new AccelerateInterpolator());objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {int foregroundAlpha = (int) ((float) animation.getAnimatedValue() * 255);/*动态设置Drawable的透明度,让前景图逐渐显示*/layerDrawable.getDrawable(INDEX_FOREGROUND).setAlpha(foregroundAlpha);BackgourndAnimationRelativeLayout.this.setBackground(layerDrawable);}});objectAnimator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {}@Overridepublic void onAnimationEnd(Animator animation) {/*动画结束后,记得将原来的背景图及时更新*/layerDrawable.setDrawable(INDEX_BACKGROUND, layerDrawable.getDrawable(INDEX_FOREGROUND));}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});}public void setForeground(Drawable drawable) {layerDrawable.setDrawable(INDEX_FOREGROUND, drawable);}//对外提供方法,用于开始渐变动画public void beginAnimation() {objectAnimator.start();}public boolean isNeed2UpdateBackground(int musicPicRes) {if (this.musicPicRes == -1) return true;if (musicPicRes != this.musicPicRes) {return true;}return false;}
}

activity_main.xml

<自定义ourndAnimationRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/rootLayout"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/ic_blackground"android:fitsSystemWindows="true"><android.support.v7.widget.Toolbar
        android:id="@+id/toolBar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:layout_alignParentTop="true"android:background="@android:color/transparent"app:subtitleTextAppearance="@style/netease_toolbar_subtitle"app:titleTextAppearance="@style/netease_toolbar_title"/><View
        android:layout_width="match_parent"android:layout_height="0.5dp"android:layout_below="@id/toolBar"android:background="#33ffffff"/><include
        android:id="@+id/discview"layout="@layout/layout_discview"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_above="@+id/rlMusicTime"android:layout_below="@id/toolBar"/><RelativeLayout
        android:id="@+id/rlMusicTime"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_above="@+id/llPlayOption"android:layout_marginEnd="15dp"android:layout_marginStart="15dp"android:layout_marginTop="10dp"><TextView
            android:id="@+id/tvCurrentTime"style="@style/neteasa_music_time_text_sytle"android:layout_alignParentStart="true"android:layout_centerVertical="true"tools:text="01:34"/><SeekBar
            android:id="@+id/musicSeekBar"style="@style/neteasa_music_time_seek_bar_sytle"android:layout_centerInParent="true"android:layout_toEndOf="@id/tvCurrentTime"android:layout_toStartOf="@+id/tvTotalTime"android:paddingEnd="15dp"android:paddingStart="15dp"/><TextView
            android:id="@+id/tvTotalTime"style="@style/neteasa_music_time_text_sytle"android:layout_alignParentEnd="true"android:layout_centerVertical="true"tools:text="05:34"/></RelativeLayout><LinearLayout
        android:id="@+id/llPlayOption"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:gravity="center"android:orientation="horizontal"android:paddingBottom="20dp"android:paddingLeft="20dp"android:paddingRight="20dp"android:paddingTop="10dp"><ImageView
            android:id="@+id/ivLast"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_last"/><ImageView
            android:id="@+id/ivPlayOrPause"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginEnd="10dp"android:layout_marginStart="10dp"android:src="@drawable/ic_play"/><ImageView
            android:id="@+id/ivNext"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_next"/></LinearLayout></自定义.model.BackgourndAnimationRelativeLayout>

layout_disc.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:gravity="center_horizontal"android:orientation="vertical"android:layout_height="match_parent"><ImageView
        android:id="@+id/ivDisc"android:layout_width="wrap_content"android:layout_height="wrap_content"/>
</LinearLayout>

layout_discview.xml

<com.自定义DiscView
    xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"><!--底盘--><ImageView
        android:id="@+id/ivDiscBlackgound"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"/><!--实现切换--><android.support.v4.view.ViewPager
        android:id="@+id/vpDiscContain"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"/><!--唱针--><ImageView
        android:id="@+id/ivNeedle"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_needle"/></com.自定义el.DiscView>

raw文件中放入本地音乐,自己从里面取资源文件

github地址 https://github.com/AchillesLzg/jianshu-neteasedisc

自定义仿网易云音乐播放界面相关推荐

  1. Android仿网易云音乐播放界面

    概述 网易云音乐是一款非常优秀的音乐播放器,尤其是播放界面,使用唱盘机风格,显得格外古典优雅.这里抛砖引玉,原文地址:http://www.jianshu.com/p/cb54990219d9 首先来 ...

  2. java4android网易云,Android仿网易云音乐播放界面

    概述 网易云音乐是一款非常优秀的音乐播放器,尤其是播放界面,使用唱盘机风格,显得格外古典优雅. 首先来看一下网易的播放效果. 要实现上面的功能,我们需要对界面进行一个拆分,拆分后大概包含如下结构: 主 ...

  3. 仿网易云音乐播放界面

    前言 网易云音乐是一款非常优秀的音乐播放器,尤其是播放界面,使用唱盘机风格,显得格外古典优雅.笔者出于学习与挑战的想法,思考播放界面背后的实现原理,并写了一个小程序. 笔者尽可能地去模仿官方的视觉.交 ...

  4. 微信小程序 --- CSS实现仿网易云音乐播放界面效果(黑胶唱片与唱针纯CSS实现)

    下面代码的效果是网易云音乐唱针和黑胶唱片的CSS效果实现方式,播放等并没贴出来 实现效果的范围 动态图效果预览: stylusW,panW是获取系统宽度计算后的参数 wxml部分: <!-- 黑 ...

  5. Android高仿网易云音乐播放界面

    现在很多的播放器的播放界面都是采用光盘的转动,下面是我仿造网易的播放界面.先上两张图: 第一张为播放前的界面,第二张为点击播放按钮的图片.布局文件如下: <RelativeLayout xmln ...

  6. 使用css动画实现网易云音乐播放界面波浪动画效果

    通过实现CSS实现仿网易云音乐播放界面动画效果,最终的效果如下 界面布局 图片也是实现滚动效果的,使用四个div,来标识每一帧波动的效果. <div class="container- ...

  7. Android仿网易云音乐播放页面 背景虚化碟片效果

    1.效果图 仿网易云音乐播放页面,主要有4个关键点: 背景虚化.获取音乐的专辑封面,将此图片作为背景图,并进行模糊虚化处理 碟片合成.获取音乐的专辑封面,和黑色碟片图片进行合成 碟片旋转.音乐播放时, ...

  8. 移动应用开发——uni-app框架 仿网易云音乐播放器学习心得

    目录 一.uni-app框架介绍 1.什么是 uni-app 2.为什么要选择uni-app 3.uni-app 统一规范 4.uni-app功能框架 二.开发工具与项目创建 1.开发工具 2.项目创 ...

  9. gulp仿移动端网易云音乐播放界面

    网易云音乐,凭借其简洁的播放界面设计.歌曲推荐系统和完善的评论机制在市场上拥有超高人气的一款音乐播放器,深受网友喜爱.所以在这个在这个举国欢庆的假日里,我的魔爪终于伸向了她. 更新: Github传送 ...

最新文章

  1. 2019-11-23 Modern Family Scripts (01 “Pilot”)
  2. java线索二叉树的实现_JAVA递归实现线索化二叉树
  3. kubernetes(一)kubeadm搭建k8s集群
  4. mfc this指针
  5. bzoj3124 [Sdoi2013]直径 直径+树形dp
  6. gis 空间分析 鸟类栖息地选取_GIS空间分析专题一:鸟儿栖息地查找
  7. nginx ---- 配置成系统服务
  8. HDU 5136 Yue Fei's Battle
  9. python rpc调用_从0到1:全面理解 RPC 远程调用
  10. 高聚合和低耦合的理解
  11. .net程序逆向之de4dot的使用
  12. [开源] PLC梯形图转指令表的算法源代码
  13. 睡眠十律 (BBC纪录片) -- 讲述10分钟获得好睡眠的方法
  14. unity il2cpp 热更实现
  15. vs2017 开关“/NOENTRY”只与 DLL 兼容;链接时不使用“/NOENTRY”
  16. 无法更新运行时文件夹共享状态_关于iPadOS 13.4更新的5件事
  17. 关于百度地图定位出现5e-324的解决办法
  18. 什么轴的机械键盘声音小
  19. i7 12700H怎么样?相当于什么级别
  20. 跨境电商业务拓展专用服务器,腾讯云海外轻量应用服务器

热门文章

  1. ET框架学习——消息系统之七
  2. NameError:name 'zhang' is not defined
  3. C#项目同时使用x86和x64版本dll库
  4. JS中修改元素内容,属性,样式的方法【详解】
  5. python编写时钟代码
  6. 2、PostgreSQL数据库介绍
  7. ElasticSearch环境配置-尚硅谷大数据培训
  8. GreatSQL项目捉虫活动(第一期)重磅来袭!
  9. 图片转文字用什么软件好?安利三个好用的方法
  10. java中反射到底是什么_JAVA中反射是什么