styles.xml
<resources>
<!-- 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">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>
</resources>
layout_discview
<?xml version="1.0" encoding="utf-8"?>
<com.example.wangxingqi.wangxingqi20180528.widget.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.example.wangxingqi.wangxingqi20180528.widget.DiscView>
activity_main
<?xml version="1.0" encoding="utf-8"?>
<com.example.wangxingqi.wangxingqi20180528.widget.BackgourndAnimationRelativeLayout
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: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"
android:layout_alignParentLeft="true" />
<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"
android:layout_toRightOf="@id/tvCurrentTime"
android:layout_toLeftOf="@+id/tvTotalTime" />
<TextView
android:id="@+id/tvTotalTime"
style="@style/neteasa_music_time_text_sytle"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
tools:text="05:34"
android:layout_alignParentRight="true" />
</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>
</com.example.wangxingqi.wangxingqi20180528.widget.BackgourndAnimationRelativeLayout>
layout_disc
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/ivDisc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
MainActivity
package com.example.wangxingqi.wangxingqi20180528;
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.Handler;
import android.os.Message;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
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.example.wangxingqi.wangxingqi20180528.model.MusicData;
import com.example.wangxingqi.wangxingqi20180528.service.MusicService;
import com.example.wangxingqi.wangxingqi20180528.utils.DisplayUtil;
import com.example.wangxingqi.wangxingqi20180528.utils.FastBlurUtil;
import com.example.wangxingqi.wangxingqi20180528.widget.BackgourndAnimationRelativeLayout;
import com.example.wangxingqi.wangxingqi20180528.widget.DiscView;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import static com.example.wangxingqi.wangxingqi20180528.widget.DiscView.DURATION_NEEDLE_ANIAMTOR;
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(){
@Override
public 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<>();
@Override
protected 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() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mTvMusicDuration.setText(duration2Time(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
stopUpdateSeekBarProgree();
}
@Override
public 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() {
@Override
public void run() {
final Drawable foregroundDrawable = getForegroundDrawable(musicPicRes);
runOnUiThread(new Runnable() {
@Override
public 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);
}
@Override
public void onMusicInfoChanged(String musicName, String musicAuthor) {
getSupportActionBar().setTitle(musicName);
getSupportActionBar().setSubtitle(musicAuthor);
}
@Override
public void onMusicPicChanged(int musicPicRes) {
try2UpdateMusicPicBackground(musicPicRes);
}
@Override
public 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;
}
}
}
@Override
public 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() {
@Override
public void run() {
optMusic(MusicService.ACTION_OPT_MUSIC_NEXT);
}
}, DURATION_NEEDLE_ANIAMTOR);
stopUpdateSeekBarProgree();
mTvMusicDuration.setText(duration2Time(0));
mTvTotalMusicDuration.setText(duration2Time(0));
}
private void last() {
mRootLayout.postDelayed(new Runnable() {
@Override
public void run() {
optMusic(MusicService.ACTION_OPT_MUSIC_LAST);
}
}, DURATION_NEEDLE_ANIAMTOR);
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 {
@Override
public 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);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMusicReceiver);
}
}
DiscView
package com.example.wangxingqi.wangxingqi20180528.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.example.wangxingqi.wangxingqi20180528.R;
import com.example.wangxingqi.wangxingqi20180528.model.MusicData;
import com.example.wangxingqi.wangxingqi20180528.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);
}
@Override
protected 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;
@Override
public void onPageScrolled(int position, float positionOffset, int
positionOffsetPixels) {
//左滑
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;
}
@Override
public void onPageSelected(int position) {
resetOtherDiscAnimation(position);
notifyMusicPicChanged(position);
if (position > currentItem) {
notifyMusicStatusChanged(MusicChangedStatus.NEXT);
} else {
notifyMusicStatusChanged(MusicChangedStatus.LAST);
}
currentItem = position;
}
@Override
public 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() {
@Override
public 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;
}
}
@Override
public 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() {
@Override
public void run() {
playAnimator();
}
}, 50);
}
}
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public 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;
}
@Override
protected 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 {
@Override
public Object instantiateItem(ViewGroup container, int position) {
View discLayout = mDiscLayouts.get(position);
container.addView(discLayout);
return discLayout;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mDiscLayouts.get(position));
}
@Override
public int getCount() {
return mDiscLayouts.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
}
BackgourndAnimationRelativeLayout
package com.example.wangxingqi.wangxingqi20180528.widget;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.animation.AccelerateInterpolator;
import android.widget.RelativeLayout;
import com.example.wangxingqi.wangxingqi20180528.R;
/**
* Created by AchillesL on 2016/11/18.
*/
/**
* 自定义一个控件,继承RelativeLayout
* */
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;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public BackgourndAnimationRelativeLayout(Context context) {
this(context, null);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public BackgourndAnimationRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public BackgourndAnimationRelativeLayout(Context context, AttributeSet attrs, int
defStyleAttr) {
super(context, attrs, defStyleAttr);
initLayerDrawable();
initObjectAnimator();
}
@RequiresApi(api = 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);
}
@SuppressLint("ObjectAnimatorBinding")
private void initObjectAnimator() {
objectAnimator = ObjectAnimator.ofFloat(this, "number", 0f, 1.0f);
objectAnimator.setDuration(DURATION_ANIMATION);
objectAnimator.setInterpolator(new AccelerateInterpolator());
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public 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() {
@Override
public void onAnimationStart(Animator animation) {
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onAnimationEnd(Animator animation) {
/*动画结束后,记得将原来的背景图及时更新*/
layerDrawable.setDrawable(INDEX_BACKGROUND, layerDrawable.getDrawable(
INDEX_FOREGROUND));
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
@RequiresApi(api = Build.VERSION_CODES.M)
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;
}
}
MusicData
package com.example.wangxingqi.wangxingqi20180528.model;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
/**
* Created by AchillesL on 2016/11/15.
*/
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;
}
}
MusicService
package com.example.wangxingqi.wangxingqi20180528.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 android.util.Log;
import com.example.wangxingqi.wangxingqi20180528.MainActivity;
import com.example.wangxingqi.wangxingqi20180528.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();
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
initMusicDatas(intent);
return super.onStartCommand(intent, flags, startId);
}
@Override
public 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);
}
@Override
public 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);
}
}
@Override
public void onCompletion(MediaPlayer mp) {
sendMusicCompleteBroadCast();
}
class MusicReceiver extends BroadcastReceiver {
@Override
public 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);
}
}
FastBlurUtil
package com.example.wangxingqi.wangxingqi20180528.utils;
import android.graphics.Bitmap;
/**
* Created by jay on 11/7/15.
*/
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
package com.example.wangxingqi.wangxingqi20180528.utils;
import android.content.Context;
/**
* Created by AchillesL on 2016/11/16.
*/
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;
}
}