自定义圆形播放按钮进度条

前言

由于我最近在公司开发的项目做一个音乐播放器,类似于咪咕音乐,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

简书地址:

http://www.jianshu.com/p/200e583e39cd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值