上次 上传gif后 没动 不知道这次会不会动 在依次吐槽 csdn的博客模板   原来要选择 无水印 我的天 gif才成功

上次写了一个音乐播放器 今天吧里面的一个效果写出来 写博客的习惯要慢慢养成 虽然平时上班忙 但是这不是借口

好了 正题开始

上面的效果 也不知道 能看到不 看不到 明天 再重新上传gif吧 家里电脑没有模拟器 做gif麻烦  回公司 在传

上面也有一些说明

圆形图片的显示 是网上的一个开源控件CircleImageView  先圆形图片的

在已有的轮子上面 稍加修改

形成上面的效果

主要是两点

进度条的绘制 来自歌曲的进度 按百分比来计算  当前播放的进度/歌曲总进度*360(一个圆)

主要是 进度条的绘制位置的确定

也就是弧形的绘制

弧形绘制 是这个RectF // 画圆弧的  画图分析 一半的一半才行

在这个CircleImageView 控件中  看懂核心就行

里面有这么一段

mBorderPaint.setStyle(Paint.Style.STROKE);  //绘制最外面的圆弧 
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);

mBitmapHeight = mBitmap.getHeight();   //显示图片的高
mBitmapWidth = mBitmap.getWidth();    //显示图片的宽

mBorderRect.set(0, 0, getWidth(), getHeight());   //一个矩形

mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2,   //绘制的圆的半径的确定
(mBorderRect.width() - mBorderWidth) / 2);

mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width()
- mBorderWidth, mBorderRect.height() - mBorderWidth);
mDrawableRadius = Math.min(mDrawableRect.height() / 2,
mDrawableRect.width() / 2);

RectF.set(mBorderWidth/2, mBorderWidth/2, getWidth()-mBorderWidth/2, 
getHeight()-mBorderWidth/2);

四个参数 确定这个矩形的 四个点

具体解释如下

修改的CircleImageView 文件

package com.daemon.musicseekbar;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;public class CircleImageView extends ImageView {private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;private static final int COLORDRAWABLE_DIMENSION = 1;private static final int DEFAULT_BORDER_WIDTH = 0;private static final int DEFAULT_BORDER_COLOR = Color.BLACK;private final RectF mDrawableRect = new RectF();private final RectF mBorderRect = new RectF();private final Matrix mShaderMatrix = new Matrix();private final Paint mBitmapPaint = new Paint();private final Paint mBorderPaint = new Paint();private int mBorderColor = DEFAULT_BORDER_COLOR;private int mBorderWidth = DEFAULT_BORDER_WIDTH;private Bitmap mBitmap;private BitmapShader mBitmapShader;private int mBitmapWidth;private int mBitmapHeight;private float mDrawableRadius;private float mBorderRadius;private boolean mReady;private boolean mSetupPending;private Paint mBorderPaint1 = new Paint();;public float newAngle; // 画弧线的角度private RectF mBorderRect1 = new RectF();private MyApplication app;public CircleImageView(Context context) {super(context);}public CircleImageView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CircleImageView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);super.setScaleType(SCALE_TYPE);app = (MyApplication) ((MainActivity)(context)).getApplication();TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.CircleImageView, defStyle, 0);mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH);mBorderColor = a.getColor(R.styleable.CircleImageView_border_color,DEFAULT_BORDER_COLOR);a.recycle();mReady = true;if (mSetupPending) {setup();mSetupPending = false;}}@Overridepublic ScaleType getScaleType() {return SCALE_TYPE;}@Overridepublic void setScaleType(ScaleType scaleType) {if (scaleType != SCALE_TYPE) {throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));}}@Overrideprotected void onDraw(Canvas canvas) {if (getDrawable() == null) {return;}canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius,mBitmapPaint); // 里面的图片canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius,mBorderPaint); // 边缘的线// 刷新 然后 在边缘 动态 画弧线if (mBorderWidth > 0) {canvas.drawArc(mBorderRect1, -90, app.newAngle, false, mBorderPaint1);}}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);setup();}public int getBorderColor() {return mBorderColor;}public void setBorderColor(int borderColor) {if (borderColor == mBorderColor) {return;}mBorderColor = borderColor;mBorderPaint.setColor(mBorderColor);invalidate();}public int getBorderWidth() {return mBorderWidth;}public void setBorderWidth(int borderWidth) {if (borderWidth == mBorderWidth) {return;}mBorderWidth = borderWidth;setup();}@Overridepublic void setImageBitmap(Bitmap bm) {super.setImageBitmap(bm);mBitmap = bm;setup();}@Overridepublic void setImageDrawable(Drawable drawable) {super.setImageDrawable(drawable);mBitmap = getBitmapFromDrawable(drawable);setup();}@Overridepublic void setImageResource(int resId) {super.setImageResource(resId);mBitmap = getBitmapFromDrawable(getDrawable());setup();}private Bitmap getBitmapFromDrawable(Drawable drawable) {if (drawable == null) {return null;}if (drawable instanceof BitmapDrawable) {return ((BitmapDrawable) drawable).getBitmap();}try {Bitmap bitmap;if (drawable instanceof ColorDrawable) {bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION,COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);} else {// 为0就自己加上需要的 要改不 就 传值 变化 或者 这里可以先测量一下?if (drawable.getIntrinsicWidth() <= 0) {int w = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); int h = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); measure(w, h); int height =getMeasuredHeight(); int width =getMeasuredWidth(); System.out.println(height +"---"+ width);bitmap = Bitmap.createBitmap(width,height,BITMAP_CONFIG);}else {bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(), BITMAP_CONFIG);}}Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());drawable.draw(canvas);return bitmap;} catch (OutOfMemoryError e) {return null;}}private void setup() {if (!mReady) {mSetupPending = true;return;}if (mBitmap == null) {return;}mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);mBitmapPaint.setAntiAlias(true);mBitmapPaint.setShader(mBitmapShader);mBorderPaint.setStyle(Paint.Style.STROKE);mBorderPaint.setAntiAlias(true);mBorderPaint.setColor(mBorderColor);mBorderPaint.setStrokeWidth(mBorderWidth);// 画弧线的mBorderPaint1.setStyle(Paint.Style.STROKE);mBorderPaint1.setAntiAlias(true);mBorderPaint1.setColor(Color.parseColor("#F08080"));mBorderPaint1.setStrokeWidth(mBorderWidth);mBitmapHeight = mBitmap.getHeight();mBitmapWidth = mBitmap.getWidth();mBorderRect.set(0, 0, getWidth(), getHeight());mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2,(mBorderRect.width() - mBorderWidth) / 2);mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width()- mBorderWidth, mBorderRect.height() - mBorderWidth);mDrawableRadius = Math.min(mDrawableRect.height() / 2,mDrawableRect.width() / 2);// 画圆弧的  画图分析 一半的一半才行mBorderRect1.set(mBorderWidth/2, mBorderWidth/2, getWidth()-mBorderWidth/2, getHeight()-mBorderWidth/2);updateShaderMatrix();invalidate();}private void updateShaderMatrix() {float scale;float dx = 0;float dy = 0;mShaderMatrix.set(null);if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width()* mBitmapHeight) {scale = mDrawableRect.height() / (float) mBitmapHeight;dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;} else {scale = mDrawableRect.width() / (float) mBitmapWidth;dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;}mShaderMatrix.setScale(scale, scale);mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth,(int) (dy + 0.5f) + mBorderWidth);mBitmapShader.setLocalMatrix(mShaderMatrix);}}

XML布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.daemon.musicseekbar.MainActivity" xmlns:app="http://schemas.android.com/apk/res/com.daemon.musicseekbar"><TextView android:layout_width="match_parent"android:layout_height="wrap_content"android:text="取出本地歌曲的前10首 随机播放一首 \n歌曲封面图片为 显示图片 \n圆形进度条随着歌曲播放而改变 \nCircleImageView 这个控件是github上面的 \n其实自定义一个也可以 但是这里有现成的轮子 就用了\n但是也 稍加修改了 因为外面的圆心进度滚动 也要计算"/><com.daemon.musicseekbar.CircleImageViewandroid:layout_centerInParent="true"android:id="@+id/civ_show"android:layout_width="200dp"android:layout_height="200dp"app:border_width="5dp"app:border_color="#ffffff"android:src="@drawable/ic_launcher"/><LinearLayout android:layout_alignParentBottom="true"android:layout_width="match_parent"android:layout_height="wrap_content"><TextView android:id="@+id/tv_music_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="歌曲名"/><Button android:id="@+id/bt_play"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="播放"/><Button android:id="@+id/bt_change"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="换一首"/></LinearLayout>
</RelativeLayout>

MainActivity  显示图片还是用了Imageloader 因为要显示 歌曲的专辑图片 眨眼方便很多 大晚上的也要睡觉了

package com.daemon.musicseekbar;import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;import android.support.v7.app.ActionBarActivity;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;public class MainActivity extends ActionBarActivity {protected static final int UPDATE_MUISC_COUNT = 0;private CircleImageView civ_show;private Cursor c;String path;private com.daemon.musicseekbar.MusicData musicDate;Handler handler = new Handler() {private int play_time;public void handleMessage(Message msg) {switch (msg.what) {case UPDATE_MUISC_COUNT:// 随机 选取一首int random = new Random().nextInt(musicDate._paths.size());path = musicDate._paths.get(random);tv_music_name.setText(musicDate._titles.get(random));String uri = "content://media/external/audio/albumart/"+ musicDate._album_ids.get(random);imageLoader.displayImage(uri, civ_show, options,new ImageLoaderSetting.AnimateFirstDisplayListener());break;case 1:// 用一个计时器 来 遍历 存在 app 中的数字play_time = mp.getCurrentPosition();app.newAngle = ((float) mp.getCurrentPosition()/ (float) mp.getDuration() * 360);// System.out.println("播放 进度  移动 角度" + app.newAngle);civ_show.invalidate();break;default:break;}};};Runnable runable = new Runnable() {@Overridepublic void run() {while (true) {SystemClock.sleep(1000);if (mp != null && mp.isPlaying()) {Message msg = Message.obtain();msg.what = 1;handler.sendMessage(msg);}}// handler.postDelayed(this, 1000); // 1s更新一次}};private TextView tv_music_name;private Button bt_play;private ImageLoader imageLoader;private DisplayImageOptions options;private Button bt_change;private MediaPlayer mp;private MyApplication app;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);app = (MyApplication) getApplication();imageLoader = ImageLoader.getInstance();configOptions();civ_show = (CircleImageView) findViewById(R.id.civ_show);tv_music_name = (TextView) findViewById(R.id.tv_music_name);bt_play = (Button) findViewById(R.id.bt_play);bt_change = (Button) findViewById(R.id.bt_change);mp = new MediaPlayer();bt_change.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stub// 随机 选取一首int random = new Random().nextInt(musicDate._paths.size());path = musicDate._paths.get(random);tv_music_name.setText(musicDate._titles.get(random));String uri = "content://media/external/audio/albumart/"+ musicDate._album_ids.get(random);imageLoader.displayImage(uri, civ_show, options,new ImageLoaderSetting.AnimateFirstDisplayListener());mp.reset();try {mp.setDataSource(path);mp.prepare();mp.start();mp.seekTo(30 * 1000);} catch (IllegalArgumentException | SecurityException| IllegalStateException | IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});bt_play.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this, path, 0).show();try {if (mp.isPlaying()) {mp.pause();} else {mp.reset();mp.setDataSource(path);mp.prepare();mp.start();mp.seekTo(30 * 1000);}} catch (IllegalArgumentException | SecurityException| IllegalStateException | IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});// 随便播放本地一首音乐getLocalMusic();new Thread(runable).start();}private void configOptions() {options = new DisplayImageOptions.Builder().showImageOnLoading(R.drawable.ic_launcher).showImageForEmptyUri(R.drawable.ic_launcher).imageScaleType(ImageScaleType.IN_SAMPLE_INT)// 图片缩放方式.showImageOnFail(R.drawable.ic_launcher).cacheInMemory(true).cacheOnDisc(true).bitmapConfig(Bitmap.Config.RGB_565)// .displayer(new RoundedBitmapDisplayer(90)).build();}private void getLocalMusic() {c = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,new String[] { MediaStore.Video.Media.TITLE, // 音乐名MediaStore.Audio.Media.DURATION, // 音乐的总时间MediaStore.Audio.Media.ARTIST, // 艺术家MediaStore.Audio.Media._ID, // id号MediaStore.Audio.Media.DISPLAY_NAME, // 音乐文件名MediaStore.Audio.Media.DATA, // 音乐文件的路径MediaStore.Audio.Media.ALBUM_ID // 封面要用的}, null,// 查询条件,相当于sql中的where语句null, // 查询条件中使用到的数据null);// 查询结果的排序方式musicDate = new MusicData();musicDate._ids = new ArrayList<Integer>();musicDate._titles = new ArrayList<String>();musicDate._paths = new ArrayList<String>();musicDate._singers = new ArrayList<String>();musicDate._album_ids = new ArrayList<Integer>();musicDate._durations = new ArrayList<Long>();// 异步加载new Thread(new Runnable() {@Overridepublic void run() {c.moveToFirst(); // 第一个for (int i = 0; i <= 10; i++) {// 大于30s才可以进来System.out.println("歌曲时间 " + c.getLong(1));if (c.getLong(1) > 30000) {musicDate._durations.add(c.getLong(1));musicDate._ids.add(c.getInt(3));musicDate._titles.add(c.getString(0));musicDate._paths.add(c.getString(5)); //musicDate._singers.add(c.getString(2));musicDate._album_ids.add(c.getInt(6));// 扫描一首 进度条 更新 上面的本地歌曲 更新 下面的 扫描地址音乐更}c.moveToNext();}// 通知 之前 将数据 保留下Message msg = Message.obtain();msg.what = UPDATE_MUISC_COUNT;handler.sendMessage(msg);}}).start();}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();if (id == R.id.action_settings) {return true;}return super.onOptionsItemSelected(item);}
}

MyApplication

package com.daemon.musicseekbar;import java.io.File;import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.utils.StorageUtils;import android.app.Application;public class MyApplication extends Application {public float newAngle=0;  //开始角度@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();//设置缓存 路径File cacheDir = StorageUtils.getOwnCacheDirectory(getApplicationContext(), "imageloader_Dting/Cache"); /*** imageload 基本配置 初始化ImageLoader*/ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())  .memoryCacheExtraOptions(100, 100).threadPoolSize(3).threadPriority(Thread.NORM_PRIORITY - 2) .denyCacheImageMultipleSizesInMemory()  .discCacheFileNameGenerator(new Md5FileNameGenerator())  .tasksProcessingOrder(QueueProcessingType.LIFO).discCache(new UnlimitedDiscCache(cacheDir))  //设置缓存路径.writeDebugLogs()//.enableLogging() // Not necessary in common .build();  ImageLoader.getInstance().init(config);  }
}

Imageloader用法 应该都会吧 相关的就不说了

MusicData  根据代码 可以自己创建实体 封装就是

基本差不多就这样了 明天看图传成功了没

android 音乐播放 圆形进度条相关推荐

  1. Vue2.0+SVG实现音乐播放圆形进度条组件,传入实时百分比实现圆圈进度动画效果

    vue2.0+SVG实现音乐播放圆形进度条组件,传入实时百分比实现圆圈进度动画效果 需求分析: 类似于大多数音乐播放器中等mini播放器控制按钮,显示播放进度,实时更新进度. progress-cir ...

  2. android音乐播放器进度条误差研究

    2019独角兽企业重金招聘Python工程师标准>>> 如何做一个"流畅"而且"准确"的进度条? 流畅!由两个条件决定,更新的频率 和 更新的 ...

  3. android音乐播放器进度条研究

    如何做一个"流畅"而且"准确"的进度条? 流畅!由两个条件决定,更新的频率 和 更新的精度 频度和精度要相适应,才能保证流畅,并不是精度越高越好,也不是频度越高 ...

  4. Android自定义控件NumberCircleProgressBar(圆形进度条)的实现

    Android自定义控件NumberCircleProgressBar(圆形进度条)的实现

  5. android 自定义音乐圆形进度条,Android自定义View实现音频播放圆形进度条

    本篇文章介绍自定义View配合属性动画来实现如下的效果 实现思路如下: 根据播放按钮的图片大小计算出圆形进度条的大小 根据音频的时间长度计算出圆形进度条绘制的弧度 通过Handler刷新界面来更新圆形 ...

  6. android实现音乐播放器(进度条)

    |--效果图 |--依赖3个对象 MediaPlayer:实现音乐播放,暂停,缓冲.     SeekBar:滑动的进度条. java.util.Timer:定时器,时时更新进度条. |--main. ...

  7. MediaPlayer 音乐播放器进度条

    今天学渣研究了一下使用MediaPlayer播放音乐时添加进度条,进度条现在用的是android自带的seekbar,后期会跟换UI的,在之前能够播放音乐的基础上,现在添加的主要功能有两个: 1实时显 ...

  8. android欢迎页圆形倒计时,android 欢迎页圆形进度条倒计时功能

    常见app欢迎页圆形进度条倒计时功能,可设置显示文字,进度条颜色,宽度,倒计时时间,内圆颜色.设置进度条类型  顺数进度条(0-100)还是倒数进度条(100-0): 先上效果图: 下面介绍实现逻辑: ...

  9. Android可触摸圆形进度条,Android 可滚动圆形进度条 滑块和进度在进度条上面跟着滚动...

    Android 可滚动圆形进度条 滑块和进度在进度条上面跟着滚动.package com.example.test; import android.content.Context; import an ...

最新文章

  1. 汉语转拼音工具、新华字典API——两个支持Python的中文资源
  2. SpringBoot第十四篇:在springboot中用redis实现消息队列
  3. Vue根据条件添加click事件
  4. 很好的阻止了事件的发生_请定好您的闹钟,八月,夜空中将发生这13件超酷的天文事件...
  5. Android UI学习 - GridView和ImageView的使用
  6. 手写实现RPC框架基础功能
  7. linux内核设计与实现 中文第三版 pdf_大牛推荐的5本 Linux 经典必读书
  8. vue watch 第一次不执行_Vue 实现前进刷新,后退不刷新的效果
  9. 前端学习(1305):项目依赖
  10. (转)OAuth 2.0的设计思路
  11. 在centos 6.5下安装svn (Subversion)
  12. bShare一个强大的网页分享插件
  13. 计算机网络原理填空题
  14. linux环境 下载Neo4j
  15. 40163 php,【PHP】微信支付JsApi 40163错误,_PHP_ 少侠科技
  16. 浅谈一下量化交易与程序化交易
  17. 实现内网穿透,个人电脑秒变服务器
  18. mongodb 服务器性能监控,MongoDB监控
  19. 青春期玩游戏不想上学怎么办?
  20. 粤嵌6818开发板项目

热门文章

  1. 解决苹果手机微信音视频不能自动播放问题
  2. 洛谷:P1129 [ZJOI2007] 矩阵游戏
  3. 学校带学院结尾,是我的锅吗?但就算如此,二本渣院的我还是拿到了阿里的Offer
  4. 【财富空间】大势观澜2018:无问彷徨
  5. 联阳(ite) IT66021FN
  6. 创建一个可操作的主角
  7. 标准中心项目实战第二讲:使用事务消息实现店铺与仓库的数据一致性
  8. 详情页返回列表内容缓存及定位实现
  9. Unity3d Ugui 22图集Sprite Packer
  10. sqlserver常用的系统存储过程