1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > Android开发-仿网易云音乐播放器样式设计与实现

Android开发-仿网易云音乐播放器样式设计与实现

时间:2018-12-01 15:23:19

相关推荐

Android开发-仿网易云音乐播放器样式设计与实现

前 言

大家平时在听音乐时使用到的网易云音乐 Android 版 App 时有没有发现网易云音乐的 App 样式做的比较好,App 抽屉式菜单栏使用 Android 独有的特性(相对于IOS) Material Design 风格的设计模式,App 整体风格设计样式符合人性设计。那么这篇博客主要讲如何实现仿网易云音乐简易版播放器。

需求分析

要实现仿网易云音乐简易版播放器的功能,需要实现以下几个功能和步骤:

自定义音乐播放器 View 的样式;实现播放和暂停音乐时指针和光盘的动画效果;实现音乐后台播放的服务。

自定义音乐播放器 View 的样式以及指针和光盘的动画效果

创建一个 xml 布局 play_music.xml 文件,布局样式如下:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"android:layout_width="wrap_content"android:layout_height="wrap_content"><!-- 光盘 --><FrameLayoutandroid:id="@+id/fl_play_music"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="90dp"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/disc" /><!-- CircleImageView --><de.hdodenhof.circleimageview.CircleImageViewandroid:id="@+id/iv_icon"android:layout_width="210dp"android:layout_height="210dp"android:layout_gravity="center"app:civ_border_color="@android:color/black"app:civ_border_width="2dp" /><ImageViewandroid:id="@+id/iv_play"android:layout_width="60dp"android:layout_height="60dp"android:layout_gravity="center"android:src="@drawable/play_music"android:visibility="gone" /></FrameLayout><!-- 指针 --><ImageViewandroid:id="@+id/iv_needle"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:layout_marginStart="25dp"android:src="@drawable/needle" /></FrameLayout>

布局主要包含播放音乐的光盘和指针以及光盘内音乐封面和播放按钮。

创建自定义 View 文件 PlayMusicView.java,逻辑代码如下:

public class PlayMusicView extends FrameLayout {private Context mContext;private MusicModel mMusicModel;private MusicService.MusicBind mMusicBinder;private Intent mServiceIntent;private boolean isPlaying, isBindService;private View mView;private FrameLayout mFlPlayMusic;private ImageView mIvIcon, mIvNeedle, mIvPlay;private Animation mPlayMusicAnim, mPlayNeedleAnim, mStopNeedleAnim;public PlayMusicView(@NonNull Context context) {super(context);init(context);}public PlayMusicView(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);init(context);}public PlayMusicView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public PlayMusicView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);init(context);}private void init(Context context) {// MediaPlayermContext = context;mView = LayoutInflater.from(mContext).inflate(R.layout.play_music, this, false);mFlPlayMusic = mView.findViewById(R.id.fl_play_music);mFlPlayMusic.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {trigger();}});mIvIcon = mView.findViewById(R.id.iv_icon);mIvNeedle = mView.findViewById(R.id.iv_needle);mIvPlay = mView.findViewById(R.id.iv_play);/*** 1、定义所需要执行的动画*1、光盘转动的动画*2、指针指向光盘的动画*3、指针离开光盘的动画* 2、startAnimation*/mPlayMusicAnim = AnimationUtils.loadAnimation(mContext, R.anim.play_music_anim);mPlayNeedleAnim = AnimationUtils.loadAnimation(mContext, R.anim.play_needle_anim);mStopNeedleAnim = AnimationUtils.loadAnimation(mContext, R.anim.stop_needle_anim);addView(mView);}/*** 切换播放状态*/private void trigger() {if (isPlaying) {stopMusic();} else {playMusic();}}/*** 播放音乐*/public void playMusic() {isPlaying = true;mIvPlay.setVisibility(View.GONE);mFlPlayMusic.startAnimation(mPlayMusicAnim);mIvNeedle.startAnimation(mPlayNeedleAnim);// 启动服务startMusicService();}/*** 停止播放*/public void stopMusic() {isPlaying = false;mIvPlay.setVisibility(View.VISIBLE);mFlPlayMusic.clearAnimation();mIvNeedle.startAnimation(mStopNeedleAnim);mMusicBinder.stopMusic();}/*** 设置光盘中显示的音乐封面图片*/private void setMusicIcon() {Glide.with(mContext).load(mMusicModel.getPoster()).into(mIvIcon);}/*** 设置音乐播放模型*/public void setMusic(MusicModel musicModel) {this.mMusicModel = musicModel;setMusicIcon();}/*** 启动音乐服务*/private void startMusicService() {if (mServiceIntent == null) {mServiceIntent = new Intent(mContext, MusicService.class);mContext.startService(mServiceIntent);} else {mMusicBinder.playMusic();}// 当前未绑定,绑定服务,同时修改绑定状态if (!isBindService) {isBindService = true;mContext.bindService(mServiceIntent, conn, Context.BIND_AUTO_CREATE);}}/*** 销毁方法,需要在 activity 被销毁的时候调用*/public void destroy() {// 如果已绑定服务,则解除绑定,同时修改绑定状态if (isBindService) {isBindService = false;mContext.unbindService(conn);}}ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mMusicBinder = (MusicService.MusicBind) service;mMusicBinder.setMusic(mMusicModel);mMusicBinder.playMusic();}@Overridepublic void onServiceDisconnected(ComponentName name) {}};}

该逻辑代码主要实现了音乐播放时所要执行的动画效果,比如:光盘转动的动画、指针指向光盘的动画以及指针离开光盘的动画。还有播放和暂停音乐时切换音乐的播放状态样式和后台服务等。

然后在创建一个用来显示播放器界面的 PlayMusicActivity.java 文件,逻辑代码如下:

public class PlayMusicActivity extends AppCompatActivity {public static final String NAME = "name";public static final String POSTER = "poster";public static final String PATH = "path";public static final String AUTHOR = "author";private String mName;private String mPoster;private String mPath;private String mAuthor;private MusicModel mMusicModel;@BindView(R.id.iv_bg)ImageView mIvBg;@BindView(R.id.tv_name)TextView mTvName;@BindView(R.id.tv_author)TextView mTvAuthor;@BindView(R.id.play_music_view)PlayMusicView mPlayMusicView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_play_music);// 隐藏状态栏getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);initView();}private void initView() {ButterKnife.bind(this);mName = getIntent().getStringExtra(NAME);mPoster = getIntent().getStringExtra(POSTER);mPath = getIntent().getStringExtra(PATH);mAuthor = getIntent().getStringExtra(AUTHOR);mMusicModel = new MusicModel();mMusicModel.setName(mName);mMusicModel.setPath(mPath);mMusicModel.setPoster(mPoster);mMusicModel.setAuthor(mAuthor);Glide.with(this).load(mMusicModel.getPoster())// 设置音乐播放器背景图片的高斯模糊度.apply(RequestOptions.bitmapTransform(new BlurTransformation(25, 35))).into(mIvBg);mTvName.setText(mMusicModel.getName());mTvAuthor.setText(mMusicModel.getAuthor());mPlayMusicView.setMusic(mMusicModel);mPlayMusicView.playMusic();}/*** 后退按钮点击事件*/public void onBackClick(View view) {onBackPressed();}@Overrideprotected void onDestroy() {super.onDestroy();mPlayMusicView.destroy();}}

其中的代码 apply(RequestOptions.bitmapTransform(new BlurTransformation(25, 35))) 是使用图片加载框架 Glide 和 glide-transformations 来实现音乐播放器背景图片的高斯模糊效果,其中 BlurTransformation 第一个参数是采集图片的半径,第二个参数是采集率。

实现音乐后台播放的服务

当音乐播放时我们要把音乐播放的操作放在后台服务,我们创建一个音乐服务文件 MusicService.java ,逻辑代码如下:

/*** 1、通过Service 连接 PlayMusicView 和 MediaPlayHelper* 2、PlayMusicView -- Service:* 1、播放音乐、暂停音乐* 2、启动Service、绑定Service、解除绑定Service* 3、MediaPlayHelper -- Service:* 1、播放音乐、暂停音乐* 2、监听音乐播放完成,停止 Service*/public class MusicService extends Service {// 不可为 0public static final int NOTIFICATION_ID = 1;private MediaPlayerHelp mMediaPlayerHelp;private MusicModel mMusicModel;public MusicService() {}public class MusicBind extends Binder {/*** 设置音乐(MusicModel)*/public void setMusic(MusicModel musicModel) {mMusicModel = musicModel;startForeground();}/*** 播放音乐*/public void playMusic() {/*** 1、判断当前音乐是否是已经在播放的音乐* 2、如果当前的音乐是已经在播放的音乐的话,那么就直接执行start方法* 3、如果当前播放的音乐不是需要播放的音乐的话,那么就调用setPath的方法*/if (mMediaPlayerHelp.getPath() != null&& mMediaPlayerHelp.getPath().equals(mMusicModel.getPath())) {mMediaPlayerHelp.start();} else {mMediaPlayerHelp.setPath(mMusicModel.getPath());mMediaPlayerHelp.setOnMeidaPlayerHelperListener(new MediaPlayerHelp.OnMeidaPlayerHelperListener() {@Overridepublic void onPrepared(MediaPlayer mp) {mMediaPlayerHelp.start();}@Overridepublic void onCompletion(MediaPlayer mp) {stopSelf();}});}}/*** 暂停播放*/public void stopMusic() {mMediaPlayerHelp.pause();}}@Overridepublic IBinder onBind(Intent intent) {return new MusicBind();}@Overridepublic void onCreate() {super.onCreate();mMediaPlayerHelp = MediaPlayerHelp.getInstance(this);}/*** 系统默认不允许不可见的后台服务播放音乐,* Notification ,*//*** 设置服务在前台可见*/private void startForeground() {/*** 通知栏点击跳转的intent*/PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,MainActivity.class), PendingIntent.FLAG_CANCEL_CURRENT);/*** 创建Notification*/Notification notification = null;/*** android API 26 以上 NotificationChannel 特性适配*/if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {NotificationChannel channel = createNotificationChannel();notification = new Notification.Builder(this, channel.getId()).setContentTitle(mMusicModel.getName()).setContentText(mMusicModel.getAuthor()).setSmallIcon(R.mipmap.ic_launcher).setContentIntent(pendingIntent).build();NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);notificationManager.createNotificationChannel(channel);} else {notification = new Notification.Builder(this).setContentTitle(mMusicModel.getName()).setContentText(mMusicModel.getAuthor()).setSmallIcon(R.mipmap.ic_launcher).setContentIntent(pendingIntent).build();}/*** 设置 notification 在前台展示*/startForeground(NOTIFICATION_ID, notification);}@RequiresApi(api = Build.VERSION_CODES.O)private NotificationChannel createNotificationChannel() {String channelId = "CloudMusic";String channelName = "CloudMusicTestService";String Description = "CloudMusicTest";NotificationChannel channel = new NotificationChannel(channelId,channelName, NotificationManager.IMPORTANCE_HIGH);channel.setDescription(Description);channel.enableLights(true);channel.setLightColor(Color.RED);channel.enableVibration(true);channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});channel.setShowBadge(false);return channel;}}

该逻辑代码的主要功能实现了启动音乐 Service 和解绑音乐 Service 的操作以及音乐播放时把音乐播放的状态显示到通知栏里。当开始播放音乐时,如果音乐 Service 进程已经被解绑或者“杀死”掉则重新开启音乐 Service ,如果当前有其它音乐正在播放,那么先结束上一个的音乐播放再进行当前播放当前的音乐等。

界面运行效果图如下:

apk安装包下载体验地址:

可以扫描以下二维码进行下载安装,或者点击以下链接 http://app.fukaimei.top/CloudMusicTest 进行下载安装体验。

———————— The end ————————

码字不易,如果您觉得这篇博客写的比较好的话,可以赞赏一杯咖啡吧~~

Demo程序源码下载地址一(GitHub)

Demo程序源码下载地址二(码云)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。