上次 上传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;
}
}
@Override
public ScaleType getScaleType() {
return SCALE_TYPE;
}
@Override
public void setScaleType(ScaleType scaleType) {
if (scaleType != SCALE_TYPE) {
throw new IllegalArgumentException(String.format(
"ScaleType %s not supported.", scaleType));
}
}
@Override
protected 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);
}
}
@Override
protected 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();
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
mBitmap = bm;
setup();
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
mBitmap = getBitmapFromDrawable(drawable);
setup();
}
@Override
public 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布局
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() {
@Override
public 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;
@Override
protected 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() {
@Override
public 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 block
e.printStackTrace();
}
}
});
bt_play.setOnClickListener(new OnClickListener() {
@Override
public 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 block
e.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();
musicDate._titles = new ArrayList();
musicDate._paths = new ArrayList();
musicDate._singers = new ArrayList();
musicDate._album_ids = new ArrayList();
musicDate._durations = new ArrayList();
// 异步加载
new Thread(new Runnable() {
@Override
public 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();
}
@Override
public 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;
}
@Override
public 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; //开始角度
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.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);
}
}
MusicData 根据代码 可以自己创建实体 封装就是
基本差不多就这样了 明天看图传成功了没