CD状图片
我在写音乐播放器的时候,在播放界面需要CD状图片,这里我们就要自定义控件了,因为系统中没有自带的这种控件。(关于自定义控件可以看我这篇博客:传送门)
因为CD图片肯定是要载入图片的,所以我们直接继承ImageView就好了。然后在OnMeasure方法中进行大小的测量,OnDraw方法中进行样式的绘制。
package com.gin.xjh.shin_music.view;
import android.content.Context;
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.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
public class cd_ImageView extends android.support.v7.widget.AppCompatImageView {
private Paint mPaint; //画笔
private int mRadius; //圆形图片的半径
private float mScale; //图片的缩放比例
public cd_ImageView(Context context) {
super(context);
}
public cd_ImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public cd_ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//因为是圆形图片,所以应该让宽高保持一致
int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRadius = size / 2;
setMeasuredDimension(size, size);
}
@Override
protected void onDraw(Canvas canvas) {
mPaint = new Paint();
Bitmap bitmap = drawableToBitmap(getDrawable());
//初始化BitmapShader,传入bitmap对象
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//计算缩放比例
mScale = (mRadius * 0.7f * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());
Matrix matrix = new Matrix();
matrix.setScale(mScale, mScale);
bitmapShader.setLocalMatrix(matrix);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
//画圆形,指定好中心点坐标、半径、画笔
mPaint.setShader(bitmapShader);
canvas.translate(mRadius * 0.30f, mRadius * 0.30f);
//canvas.rotate(degree, mRadius * 0.7f, mRadius * 0.7f);
canvas.drawCircle(mRadius * 0.7f, mRadius * 0.7f, mRadius * 0.7f, mPaint);
}
//写一个drawble转BitMap的方法
private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
drawable.draw(canvas);
return bitmap;
}
}
主要将下面这几条代码注释一下,这些代码是主要的测量及绘制:
OnMeasure中:
int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRadius = size / 2;
setMeasuredDimension(size, size);
因为传入的图片可能宽高是不同的,所以我们画圆形图片不要留白,所以取最小值,然后圆形图片的半径应该就是这个的一半
OnDraw中:
mScale = (mRadius * 0.7f * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());
Matrix matrix = new Matrix();
matrix.setScale(mScale, mScale);
计算缩放的比例,因为CD样式,所以我们在结合控件大小还需要缩小到70%,所以需要乘上0.7
canvas.translate(mRadius * 0.30f, mRadius * 0.30f);
canvas.drawCircle(mRadius * 0.7f, mRadius * 0.7f, mRadius * 0.7f, mPaint);
因为先画了一个原本大小的黑色圆形。然后我们要画中间的图片了,但是不能直接画,因为现在图片的坐标系是需要变化的,记住translate方法并不是移动画布而是移动坐标系,然后把Bitmap画上去就好了。
旋转,暂停及恢复
方法一:通过线程进行计时然后对Canvas进行旋转
因为我们需要不断的刷新界面,所以不推荐使用。
private volatile float degree = 0;//角度
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
@Override
public void run() {
synchronized (cd_ImageView.class) {
degree += 2f;
if (degree > 360f) {
degree -= 360f;
}
invalidate();//重新绘制View
handler.postDelayed(this, 16l);
}
}
};
不断的计算角度,通过handler的计时重新调用来不断的重新绘制View。
onDraw中绘制CD图片之前添加:
canvas.rotate(degree, mRadius * 0.7f, mRadius * 0.7f);
开始,暂停,恢复代码
public void start() {
handler.post(runnable);
}
public void pause() {
handler.removeCallbacks(runnable);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
handler.removeCallbacksAndMessages(null);
}
通过动画实现
我们设定好动画的属性:
//设定动画作用于的控件,以及什么动画,旋转的开始角度和结束角度
objAnim = ObjectAnimator.ofFloat(mAlbum, "rotation", 0.0f, 360.0f);
//设定动画的旋转周期
objAnim.setDuration(20000);
//设置动画的插值器,这个为匀速旋转
objAnim.setInterpolator(new LinearInterpolator());
//设置动画为无限重复
objAnim.setRepeatCount(-1);
//设置动画重复模式
objAnim.setRepeatMode(ObjectAnimator.RESTART);
动画开始
objAnim.start();
动画暂停
objAnim.pause();
动画恢复
objAnim.resume();
动画停止
objAnim.end();
对控件清除动画
mAlbum.clearAnimation();
效果如下: