前言
由于我最近在公司开发的项目做一个音乐播放器,类似于咪咕音乐,qq音乐,网易云音乐。刚开始的需求还只是做一些简单的播放音乐功能,播放按钮也是直接拿UI给的图标,还不需要搞什么在按钮上显示进度之类的,小日子过的还算轻松,没什么大鸭梨。可是后来我们伟大的产品经理说要在歌曲列表上添加一个播放按钮,按钮上还能显示歌曲播放的进度和状态,状态分三种:默认,正在播放,结束。
类似于
结束_橙色.png 暂停_橙色.png
当然,这需求并不复杂,相信学过自定义控件的朋友都有思路,而我也一开始就想到了两个解决方案:
方案一
做一个圆形播放进度的自定义view,然后根据进度控制播放的状态,例如在暂停时,替换成UI给的图标,结束时,用播放结束的图标。这个方案优点是省时省事,但是有个缺点,就是很难使自定义view的大小和ui给的图标随手机屏幕分辨率的改变保持一致
方案二
徒手画一个播放按钮,含有播放进度功能和根据播放进度画出不同的播放状态。这个方案的有点很明显,解决了方案一的缺点,但是却就是麻烦了一点,需要把图标画出来,还要控制状态。
最终我选择了方案二,因为这方案虽然麻烦了一点,但能解决是安卓机型的适配问题啊!还有能随时自定义图标的颜色,根据UI给的图标,播放按钮不止一个颜色,如果用方案一可能多用好几个图标。
1.在 attr.xml 中设置播放进度条的属性
<!--自定义进度条-->
<declare-styleable name="CustomProgress">
<attr name="radius" format="dimension" /><!--半径-->
<attr name="strokeWidth" format="dimension" /><!--画笔宽度-->
<attr name="circleColor" format="color" /><!--内圆颜色-->
<attr name="ringColor" format="color" /><!--进度条颜色-->
<attr name="totalProgress" format="integer" /><!--总进度-->
<attr name="textColor" format="color|reference" /><!--字体颜色-->
<attr name="bigCircleColor" format="color" /><!--外圆颜色-->
<attr name="rectColor" format="color" /><!--中间双竖暂停的颜色-->
</declare-styleable>
2.初始化自定义属性
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray typeArray = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.CustomProgress, 0, 0);
mRadius = typeArray.getDimension(R.styleable.CustomProgress_radius, 300);
mStrokeWidth = typeArray.getDimension(R.styleable.CustomProgress_strokeWidth, 20);
mCircleColor = typeArray.getColor(R.styleable.CustomProgress_circleColor, Color.BLUE);
mRingColor = typeArray.getColor(R.styleable.CustomProgress_ringColor, Color.RED);
mTotalProgress = typeArray.getInt(R.styleable.CustomProgress_totalProgress, 100);
mTextColor = typeArray.getColor(R.styleable.CustomProgress_textColor, Color.WHITE);
mBigCircleColor = typeArray.getColor(R.styleable.CustomProgress_bigCircleColor, Color.WHITE);
mRectColor = typeArray.getColor(R.styleable.CustomProgress_rectColor, Color.WHITE);
txt = "1";
typeArray.recycle();//注意这里要释放掉
mRingRadius = mRadius + mStrokeWidth / 2;
}
3.实现onDraw方法
protected void onDraw(Canvas canvas) {
//计算中心点
mXCenter = getWidth() / 2;
mYCenter = getHeight() / 2;
//未开始播放状态,默认显示文字,这里默认设置为1
if (isNormal) {
//计算文字长度
mTxtWidth = mTextPaint.measureText(txt, 0, txt.length());
//在中心点画文字
canvas.drawText(txt, mXCenter - mTxtWidth / 2, mYCenter + mTxtHeight / 4, mTextPaint);
return;
}
//正在播放状态或者结束状态的时候 画圆环
canvas.drawCircle(mXCenter, mYCenter, mRadius + mStrokeWidth / 2, mBigPatient);
canvas.drawCircle(mXCenter, mYCenter, mRadius, mCirclePaint);
//判断是正在播放还是结束状态
if (!isFinish) {
//正在播放状态,画出中间双竖
canvas.drawLine(mXCenter - mRadius / 4, mYCenter - mRadius / 2 - mStrokeWidth / 4, mXCenter - mRadius / 4, mYCenter + mRadius / 2 + mStrokeWidth / 4, mRectPaint);
canvas.drawLine(mXCenter + mRadius / 4, mYCenter - mRadius / 2 - mStrokeWidth / 4, mXCenter + mRadius / 4, mYCenter + mRadius / 2 + mStrokeWidth / 4, mRectPaint);
} else {
//结束播放状态,画三角形
canvas.drawLine(mXCenter - mRadius / 4, mYCenter - mRadius / 2 - mStrokeWidth / 5, mXCenter - mRadius / 4, mYCenter + mRadius / 2 + mStrokeWidth / 5, mBigPatient);
canvas.drawLine(mXCenter + mRadius / 2, mYCenter, mXCenter - mRadius / 4, mYCenter - mRadius / 2, mBigPatient);
canvas.drawLine(mXCenter + mRadius / 2 + mStrokeWidth / 5, mYCenter, mXCenter - mRadius / 4, mYCenter + mRadius / 2, mBigPatient);
return;
}
//根据进度画圆弧
if (mProgress > 0) {
RectF oval = new RectF();
oval.left = (mXCenter - mRingRadius);
oval.top = (mYCenter - mRingRadius);
oval.right = mRingRadius * 2 + (mXCenter - mRingRadius);
oval.bottom = mRingRadius * 2 + (mYCenter - mRingRadius);
canvas.drawArc(oval, -90, ((float) mProgress / mTotalProgress) * 360, false, mRingPaint); //
if (mProgress == 100) {
isFinish = true;
mBigPatient.setColor(mRectColor);
}
}
}
4.对外暴露设置一些关键属性的方法
//设置进度的方法
public void setProgress(int progress) {
mProgress = progress;
postInvalidate();
}
//设置总进度
public void setmTotalProgress(int totalProgress) {
mTotalProgress = totalProgress;
}
//设置当前的按钮的播放状态
public void setStatus(int status) {
switch (status) {
case NORMAL_STATUS:
isNormal = true;
mBigPatient.setColor(Color.WHITE);
postInvalidate();
break;
case START_STATUS:
isFinish = false;
isNormal = false;
mBigPatient.setColor(Color.parseColor("#95ffffff"));
break;
case FINISH_STATUS:
isFinish = true;
isNormal = false;
mBigPatient.setColor(mRectColor);
postInvalidate();
break;
}
}
//设置默认状态的文字
public void setText(String text) {
this.txt = text;
}
//设置中间双竖的方法
public void setRectColor(int color) {
this.mRectColor = color;
mRectPaint.setColor(mRectColor);
}
演示
test.gif最后附上源码地址:
https://github.com/zeschi/PlaySongCircleProgresssDemo/tree/master
网友评论