目录

  • 一、MyServer的用法
  • 二、仿网易云音乐播放器设计思路
    • (一)网易云播放器构成分析
    • (二)MusicDemo实现功能
      • a. MediaServer播放音乐?
      • b. Seekbar滑动条及时间进度
      • c. 唱针旋转和碟片旋转
      • d.隐藏上边框
  • 三、具体编码
    • 附:本次项目源码

一、MyServer的用法

(一)原理

Service
是android四大组件之一,主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。而Service是运行在主线程里的,如果直接在Service中处理一些耗时的逻辑,就会导致程序ANR,所以需要另外开启子线程来处理。
两种模式: startService()/bindService()
基本用法:
新建MyService继承自Service;
不要忘了在AndroidManifest.xml中注册
MyService Service启动后如果没有StopService操作即使activity被销毁任然会在后台运行

(二)用法
方法一:在java包下,右键选择Server新建MediaServer,这样在AndroidManifest下会自动生成服务;



方法二:自定义MediaServer.java类,继承Server,然后在AndroidManifest里添加:

.....略</activity><serviceandroid:name=".MediaService"android:enabled="true"android:exported="true" /></application>
略.....

二、仿网易云音乐播放器设计思路

(一)网易云播放器构成分析

主要包含:
1.播放组键功能,2.歌曲进度条功能, 3.唱片特效功能,4.隐藏上边框

原网易云效果图和我的仿网易云音乐播放器Demo中的对比图:

(二)MusicDemo实现功能

a. MediaServer播放音乐?


main.java部分函数截图:

  • 定义及声明:
  • 的点击事件

b. Seekbar滑动条及时间进度

绑定Server的前提下,run()函数定义seekbar的滚动及test时间值,调用方法放在对button的监听Onclick函数中;

  • seekbar及textSwitcher的定义:
  • Oncreate函数中的相关部分声明:

    自定义run()函数,控制播放到当前音乐的滑动条时间设置:

c. 唱针旋转和碟片旋转


d.隐藏上边框

自定义styles,在main函数调用

main函数中:

    //设置透明栏if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {Window window = getWindow();window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);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);}


自定义styles.xml:

<resources><style name="AppTheme.Base" parent="Theme.AppCompat.Light"><item name="windowActionBar">false</item><item name="windowNoTitle">true</item></style><style name="BaseAppTheme" parent="AppTheme.Base"><!-- Customize your theme here. --><item name="colorPrimary">@color/colorPrimary</item><item name="colorPrimaryDark">@color/colorPrimaryDark</item><item name="colorAccent">@color/colorAccent</item></style><!-- Base application theme. --><style name="AppTheme" parent="BaseAppTheme"><item name="android:windowTranslucentStatus">true</item></style>
</resources>

三、具体编码

项目结构图:

注意:因为drawable不支持mp3格式,所以要把mp3文件放在如图新建的raw文件夹中:

准备文件:
图片:上一首,下一首,播放键,暂停键,唱针,唱片,模糊背景图

源码:
main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/music_play_background"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="60dp"android:layout_marginTop="10dp"android:layout_alignParentTop="true"android:id="@+id/title"android:orientation="horizontal"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="15dp"android:layout_marginBottom="3dp"android:text="Quit Inside"android:textSize="25dp"android:gravity="center"android:textColor="#ffffff"/></LinearLayout><TextViewandroid:layout_width="match_parent"android:layout_height="0.5dp"android:background="#afafaf"android:layout_below="@+id/title"/><ImageViewandroid:id="@+id/disc"android:layout_width="280dp"android:layout_height="280dp"android:layout_centerHorizontal="true"android:layout_below="@+id/title"android:layout_marginTop="50dp"android:src="@drawable/play_album" /><ImageViewandroid:id="@+id/needle"android:layout_width="120dp"android:layout_height="120dp"android:layout_below="@+id/title"android:src="@drawable/play_needle"android:layout_marginLeft="150dp"/><RelativeLayoutandroid:id="@+id/music1"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_above="@+id/rl"android:layout_marginTop="20dp"android:layout_marginBottom="10dp"android:gravity="center"><SeekBarandroid:id="@+id/music_seek_bar"android:layout_width="240dp"android:layout_height="wrap_content"/><TextSwitcherandroid:id="@+id/text_switcher"android:layout_width="80dp"android:layout_height="50dp"android:layout_toRightOf="@+id/music_seek_bar"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="00:00/2:00"android:textColor="@color/colorAccent"/></TextSwitcher></RelativeLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="70dp"android:gravity="center"android:id="@+id/rl"android:layout_marginBottom="20dp"android:layout_alignParentBottom="true"android:orientation="horizontal"><ImageViewandroid:id="@+id/playing_pre"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:src="@drawable/music_previous" /><ImageViewandroid:id="@+id/playing_play"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:src="@drawable/music_pause" /><ImageViewandroid:id="@+id/playing_next"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:src="@drawable/music_next" /></LinearLayout>
</RelativeLayout>

MediaServer.java:

按照方法一新建MediaServer.java内容:

package com.example.cungu.musicdemo;import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;import java.io.IOException;public class MediaService extends Service {private MediaPlayer mPlayer;/** 绑定服务的实现流程:* 1.服务 onCreate, onBind, onDestroy 方法* 2.onBind 方法需要返回一个 IBinder 对象* 3.如果 Activity 绑定,Activity 就可以取到 IBinder 对象,可以直接调用对象的方法*/// 相同应用内部不同组件绑定,可以使用内部类以及Binder对象来返回。public class MusicController extends Binder {public void play() {mPlayer.start();//开启音乐}public void pause() {mPlayer.pause();//暂停音乐}public long getMusicDuration() {return mPlayer.getDuration();//获取文件的总长度}public long getPosition() {return mPlayer.getCurrentPosition();//获取当前播放进度}public void setPosition (int position) {mPlayer.seekTo(position);//重新设定播放进度}}/*** 当绑定服务的时候,自动回调这个方法* 返回的对象可以直接操作Service内部的内容* @param intent* @return*/@Overridepublic IBinder onBind(Intent intent) {return new MusicController();}@Overridepublic void onCreate() {super.onCreate();mPlayer = MediaPlayer.create(this, R.raw.music1);}/*** 任意一次unbindService()方法,都会触发这个方法* 用于释放一些绑定时使用的资源* @param intent* @return*/@Overridepublic boolean onUnbind(Intent intent) {return super.onUnbind(intent);}@Overridepublic void onDestroy() {if (mPlayer.isPlaying()) {mPlayer.stop();}mPlayer.release();mPlayer = null;super.onDestroy();}
}

main.java:

package com.example.cungu.musicdemo;import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Build;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextSwitcher;import java.text.SimpleDateFormat;
import java.util.Date;public class MainActivity extends AppCompatActivity implements View.OnClickListener,Runnable, ServiceConnection, SeekBar.OnSeekBarChangeListener {private ImageView disc,needle,playingPre,playingPlay,playingNext;private ObjectAnimator discAnimation,needleAnimation;//自定义指针和唱盘private boolean isPlaying = true;//0,1 判断是否处于播放状态//声明服务private static final String TAG = MainActivity.class.getSimpleName();private MediaService.MusicController mMusicController;//使用方法:mMusicController.play();播放   mMusicController.pause();暂停private boolean running;private TextSwitcher mSwitcher;private SeekBar mSeekBar;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//设置透明栏if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {Window window = getWindow();window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);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);}//滑动条部分mSeekBar = (SeekBar) findViewById(R.id.music_seek_bar);mSeekBar.setOnSeekBarChangeListener(this);mSwitcher = (TextSwitcher) findViewById(R.id.text_switcher);mSwitcher.setInAnimation(this, android.R.anim.fade_in);mSwitcher.setOutAnimation(this, android.R.anim.fade_out);Intent intent = new Intent(this, MediaService.class);//增加StartService,来增加后台播放功能startService(intent);// 绑定服务,使用context来绑定// 那个界面需要绑定 就用哪个 Activity// 参数1:Intent               代表需要绑定哪一个Service// 参数2:ServiceConnection    回调接口,可以接收到Service连接成功和断开的回调,成功就可以取到对象。// 绑定服务 参数2就是服务和指定的对象绑定在一起bindService(intent, this, BIND_AUTO_CREATE);//指针和唱片部分initViews();//定义背景图setAnimations();}private void initViews() {playingPre = (ImageView) findViewById(R.id.playing_pre);playingPlay = (ImageView) findViewById(R.id.playing_play);playingNext = (ImageView) findViewById(R.id.playing_next);disc = (ImageView) findViewById(R.id.disc);needle = (ImageView) findViewById(R.id.needle);playingPre.setOnClickListener(this);playingPlay.setOnClickListener(this);playingNext.setOnClickListener(this);}//动画设置private void setAnimations() {discAnimation = ObjectAnimator.ofFloat(disc, "rotation", 0, 360);discAnimation.setDuration(20000);discAnimation.setInterpolator(new LinearInterpolator());discAnimation.setRepeatCount(ValueAnimator.INFINITE);needleAnimation = ObjectAnimator.ofFloat(needle, "rotation", 0, 25);needle.setPivotX(0);needle.setPivotY(0);needleAnimation.setDuration(800);needleAnimation.setInterpolator(new LinearInterpolator());}@Overridepublic void onClick(View v) {int id = v.getId();switch (id) {//前一曲case R.id.playing_pre:if (discAnimation != null) {discAnimation.end();playing();}break;//播放中case R.id.playing_play:if (isPlaying){playing();}else {if (needleAnimation != null) {needleAnimation.reverse();needleAnimation.end();mMusicController.pause();}if (discAnimation != null && discAnimation.isRunning()) {discAnimation.cancel();mMusicController.pause();float valueAvatar = (float) discAnimation.getAnimatedValue();discAnimation.setFloatValues(valueAvatar, 360f + valueAvatar);}playingPlay.setImageResource(R.drawable.music_play);isPlaying = true;}break;//下一曲case R.id.playing_next:if (discAnimation != null) {discAnimation.end();playing();}break;default:break;}}//播放时动画设置和图片切换private void playing(){needleAnimation.start();discAnimation.start();playingPlay.setImageResource(R.drawable.music_pause);mMusicController.play();//播放isPlaying = false;}
//===================================歌曲播放服务================================================@Overrideprotected void onStart() {super.onStart();Thread thread = new Thread(this);thread.start();}@Overrideprotected void onStop() {running = false;super.onStop();}@Overrideprotected void onDestroy() {// 解除绑定unbindService(this);super.onDestroy();}//-----------播放到当前音乐的滑动条及时间设置-------------@Overridepublic void run() {running = true;try {while (running) {if (mMusicController != null) {long musicDuration = mMusicController.getMusicDuration();final long position = mMusicController.getPosition();final Date dateTotal = new Date(musicDuration);final SimpleDateFormat sb = new SimpleDateFormat("mm:ss");mSeekBar.setMax((int) musicDuration);mSeekBar.setProgress((int) position);mSwitcher.post(new Runnable() {@Overridepublic void run() {Date date = new Date(position);String time = sb.format(date) + "/" + sb.format(dateTotal);mSwitcher.setCurrentText(time);}});}Thread.sleep(500);}} catch (InterruptedException e) {e.printStackTrace();}}//-----------------------------//服务绑定与解除绑定的回调/*** 当服务与当前绑定对象,绑定成功,服务onBind方法调用并且返回之后* 回调给这个方法** @param name* @param service IBinder 就是服务 onBind 返回的对象*/@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mMusicController = ((MediaService.MusicController) service);}@Overridepublic void onServiceDisconnected(ComponentName name) {mMusicController = null;}public void btnStopService(View view) {Intent intent = new Intent(this, MediaService.class);stopService(intent);}@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {mMusicController.setPosition(seekBar.getProgress());}
}

大功告成!

附:本次项目源码

下载地址:https://github.com/cungudafa/MusicDemo


注:
1、我在MediaServer里面只放了一首歌曲,可以完善读取手机内存的歌曲,还可以做一个listView界面来显示全部歌曲(需要创建对数据库的调用),like this;

2、真正的网易云模糊背景用了高斯模糊函数,对唱片中图像进行处理,我这里未实现,机智如我,一张模糊背景就处理掉,like this,不够效果不好;

3、还有唱片是我用绘图工具将专辑封面合成的,like this,真正网易云是用图片叠加函数,绘出来的,可以略过手工绘图,我功力不够啊!希望大佬可尝试~

我Ps合成图片:可还行~

若有大佬完善注释功能,请受我一拜!直接去网易云上班吧!

【Android】_MediaServer_仿网易云音乐播放器1(指针和唱片)相关推荐

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

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

  2. Vue仿网易云音乐播放器(一)

    项目简介 写了很多关于Vue的项目,都是一部分一部分的小模块,这次想把全部学过的关于Vue知识和模块写成一个完整的项目.都是组件化进行mvvm模式开发,实现了view和data的同步更新.仿网易云播放 ...

  3. uniapp 仿网易云音乐播放器 微信小程序

    效果视频: uniapp 仿照网易云播放器功能 效果截图: 上代码: <template><view class=""><scroll-view :s ...

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

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

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

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

  6. Vue仿网易云音乐播放器(二)

    项目运行 首先要安装npm或者cnpm和node.js环境 在终端建立vue-cli项目,命令行cnpm install vue-cli -g //全局安装 vue-cli 查看vue-cli是否成功 ...

  7. HTML+CSS+JAVASCRIPT 高仿低配网页版网易云音乐播放器 1

    HTML+CSS+JAVASCRIPT 高仿低配网页版网易云音乐播放器 前言 没有使用任何框架,只是想用最简单纯js的代码实现下 前台: Javascript+jQuery 后台: php/nodej ...

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

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

  9. 树莓派云音乐c语言,基于树莓派的红外遥控版网易云音乐播放器

    基于树莓派的红外遥控版网易云音乐播放器.下面是遥控键盘示意图: CH- CH CH+ << >> || - + EQ 0 100+ 200+ 1 2 3 4 5 6 7 8 9 ...

  10. linux树莓派网易云音乐,基于树莓派的红外遥控版网易云音乐播放器

    基于树莓派的红外遥控版网易云音乐播放器.下面是遥控键盘示意图: CH- CH CH+ << >> || - + EQ 0 100+ 200+ 1 2 3 4 5 6 7 8 9 ...

最新文章

  1. DDos攻击的一些领域知识——(流量模型针对稳定业务比较有效)不稳定业务采用流量成本的检测算法,攻击发生的时候网络中各个协议的占比发生了明显的变化...
  2. 中级软件测试笔试题100精讲_数字IC设计职位经典笔试面试100题(71~80)
  3. mysql查询大量数据报错_mysql 查询大量数据报错
  4. SpringMVC 异步交互 AJAX 文件上传
  5. python ctypes 回调函数_如何用Python中的ctypes创建回调函数?
  6. 重启小狼毫输入法,rime输入法重启
  7. java监听鼠标接口实现_自定义Java鼠标监听器?
  8. C# Base64方式的编码与解码
  9. windows导出导入mongodb数据库
  10. javascript模式 (3)——工厂模式和装饰模式
  11. Mini USB针脚定义
  12. OCR识别提取图片中文字原理
  13. 【飞书系列】—— 飞书妙记:语音转文字,视频转文字
  14. 阿里云网盘内侧注册方法
  15. Spring Boot - 让人抓狂的ClassNotFoundException
  16. 储罐液位开关c语言编程,危化品企业罐区液位计和紧急切断阀的设置及联锁要求规范合集(1)...
  17. 在背景色和背景图片同时存在的情况下,为什么还要设置背景色?
  18. 伪造微信截图工具(改)
  19. SQL数据库查询 左连接、右连接、内连接 实例
  20. 微信小程序仿京东优惠券

热门文章

  1. ResourceBundle 用法
  2. 软考_高级《系统分析师》考试大纲
  3. 雅马哈音箱的usb驱动MAC-WINDOWS
  4. 电子计算机和量子力学,通俗讲解一下量子计算机究竟是怎么运作的?其实量子力学并不深奥...
  5. TcaplusDB X 光与夜之恋|春暖花开之际与你相遇
  6. SPDY, WebSocket, WebDAV概念
  7. oracle卸载和服务问题
  8. 三峡大学学生选课系统_201014119_赵敏_三峡大学学生选课系统.doc
  9. android 半透明色值_Android应用中设置alpha值来制作透明与渐变效果的实例
  10. 技术交底书(二)-----一种基于移动终端的安全防护系统