自定义view 下载进度条

按康师傅指示 完成下载进度条自定义view 效果如下

动态图

其实主要是draw内部进行绘制 断点也给了点思路

代码很少 主要是绘制叠层和裁剪画布 可能写法不是最优解 如果有错误请指出哈 我去验证修改 (本文代码有java/kotlin) 区分状态只做到了 准备下载 、开始下载、暂停下载、完成下载 自定义view当然少不了一些简单步骤 完整代码在文章最后 自提

关键代码

	// 以下代码是java
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 设置背景 圆角矩形绘制
        mPaint.setColor(bgColor);
        canvas.drawRoundRect(new RectF(0, 0, width, height) ,100, 100, mPaint);
        // 根据状态制定绘制
        if (status == STATUS_DOWNLOAD){
            mText = mProgress + "%";
            float progressRight = mProgress / 100f * width;
            canvas.save();
            // 进度条颜色 并绘制
            mPaint.setColor(proColor);
            // 进度条 裁剪画布
            canvas.clipRect(0, 0, progressRight, height);
            // 进度条背景
            canvas.drawRoundRect(new RectF(0, 0, width, height) ,100, 100, mPaint);
            canvas.restore();
        }else if(status == STATUS_COMPLETE){
            mText ="下载完成";
        }else if(status == STATUS_PREPARE){
            mText = "点击下载";
        }else if (status == STATUS_PAUSE){
            mText = "暂停下载";
        }
        Paint.FontMetrics fm = mTextPaint.getFontMetrics();
        float y = height / 2 + (fm.descent - fm.ascent) / 2 - fm.descent;
        canvas.drawText(mText,width/2,y , mTextPaint);
    }

复制代码
	//kotlin
 override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 设置背景 圆角矩形绘制
        mPaint?.color = bgColor
        canvas.drawRoundRect(RectF(0f, 0f, width.toFloat(), height.toFloat()), 100f, 100f, mPaint!!)
        // 根据状态制定绘制
        when (status){
            STATUS_downLoad -> {
                text = "$mProgress%"
                val progressRight = mProgress / 100f * width
                canvas.save()
                // 进度条颜色 并绘制
                mPaint!!.color = progressColor
                // 进度条 裁剪画布
                canvas.clipRect(0f, 0f, progressRight, height.toFloat())
                // 进度条背景
                canvas.drawRoundRect(RectF(0f, 0f, width.toFloat(), height.toFloat()), 100f, 100f, mPaint!!)
                canvas.restore() // 释放资源
            }
            STATUS_complete -> text = "下载完成"
            STATUS_Prepare -> text = "点击下载"
            STATUS_PAUSE -> text = "暂停下载"
            else -> { }
        }
        val fm = mTextPaint?.fontMetrics
        val y = height / 2 + (fm.descent - fm.ascent) / 2 - fm.descent
        canvas.drawText(text!!, (width / 2).toFloat(), y, mTextPaint)
    }
复制代码

解析: 分为3层绘制 1.绘制背景 2.裁剪画布 绘制进度条 3.根据状态进行文本绘制

(我在绘制图层吃了亏 文本(步骤3)一直会根据进度条(步骤2)才会显示 后面按照一层层关系去调整就解决该问题了) 这只是关于绘制的部分 重要的是还是设置进度和刷新的对外方法

	//java
    /**
     * 设置进度
     */
    public void setProgress(int progress) {
        status = STATUS_DOWNLOAD;
        mProgress = progress;
        if (mProgress == 100) {
            status = STATUS_COMPLETE;
        }
        invalidate();
    }
复制代码
	//Kotlin
   /**
     * 设置进度
     */
    fun setProgress(progress: Int) {
        status = STATUS_downLoad
        mProgress = progress
        if (mProgress == 100) {
            status = STATUS_complete
        }
        invalidate() // 刷新
    }
复制代码

点击调用设置倒计时有很多方法 这里只提供了最简单的调用测试

   private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 0:
                    if (downView.isLoading()){
                        downView.setProgress(mProgress++);
                    }
                    if (mProgress <= 100)
                        mHandler.sendEmptyMessageDelayed(0, 100);
                    break;
            }
        }
    };	
	// onCreate
	downView.setOnClickListener(v-> {
             if (downView.isLoading())
                 downView.pause();
             else
                 downView.start();
         });
         mHandler.sendEmptyMessageDelayed(0, 100);
复制代码

代码如上 点击时 进行状态判断 正在下载 可进行暂停操作 再次点击可继续回复进度条

好了作业已交 完整代码如下

public class DownloadView extends View {
    public static final int STATUS_PREPARE = 1; // 准备下载
    public static final int STATUS_DOWNLOAD = 2; // 正在下载
    public static final int STATUS_PAUSE    = 3; // 暂停下载
    public static final int STATUS_COMPLETE = 4; // 完成下载
    private int status = STATUS_PREPARE;
    private int bgColor ; // 背景色
    private int proColor ; // 进度条se
    private int textColor ; // 文本颜色
    private int pauseColor ; // 暂停
    private Canvas mCanvas;
    private String mText;
    /**
     * 是否在下载
     * @return
     */
    public boolean isLoading() {
        if (status == STATUS_DOWNLOAD){
            return true;
        }
        return false;
    }


    public DownloadView(@NonNull Context context) {
        this(context,null);
    }

    public DownloadView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }
    Paint mPaint =null;
    Paint mTextPaint =null;
    public DownloadView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init (attrs);
        initPaint();
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setColor(Color.BLUE);
        mPaint.setAntiAlias(true); // 消除锯齿
        mPaint.setStyle(Paint.Style.FILL);
        mTextPaint = new Paint();
        mTextPaint.setColor(textColor);
        mTextPaint.setAntiAlias(true); // 消除锯齿
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setTextSize(18);
    }

    /**
     * 初始化
     * @param attrs
     */
    private void init(AttributeSet attrs) {
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.DownloadView);
        bgColor = typedArray.getColor(R.styleable.DownloadView_bgColor,0xFF00CC99);
        proColor = typedArray.getColor(R.styleable.DownloadView_progressColor,0x4400CC99);
        textColor = typedArray.getColor(R.styleable.DownloadView_textColor,0x4400CC99);
        pauseColor = typedArray.getColor(R.styleable.DownloadView_pauseColor,0xFFFFFFFF);
        typedArray.recycle();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

    }
    int width = 0;
    int height = 50;
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec);
        height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
    }



    public String getText() {
        return mText;
    }

    public void setText(String text) {
        mText = text;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 设置背景 圆角矩形绘制
        mPaint.setColor(bgColor);
        canvas.drawRoundRect(new RectF(0, 0, width, height) ,100, 100, mPaint);
        // 根据状态制定绘制
        if (status == STATUS_DOWNLOAD){
            mText = mProgress + "%";
            float progressRight = mProgress / 100f * width;
            canvas.save();
            // 进度条颜色 并绘制
            mPaint.setColor(proColor);
            // 进度条 裁剪画布
            canvas.clipRect(0, 0, progressRight, height);
            // 进度条背景
            canvas.drawRoundRect(new RectF(0, 0, width, height) ,100, 100, mPaint);
            canvas.restore();
        }else if(status == STATUS_COMPLETE){
            mText ="下载完成";
        }else if(status == STATUS_PREPARE){
            mText = "点击下载";
        }else if (status == STATUS_PAUSE){
            mText = "暂停下载";
        }
        Paint.FontMetrics fm = mTextPaint.getFontMetrics();
        float y = height / 2 + (fm.descent - fm.ascent) / 2 - fm.descent;
        canvas.drawText(mText,width/2,y , mTextPaint);
    }

    public void start(){
        if (status == STATUS_PREPARE ||
                status == STATUS_PAUSE) {
            status = STATUS_DOWNLOAD;
        }
    }

    public void pause (){
        if (status == STATUS_DOWNLOAD) {
            status = STATUS_PAUSE;
        }
        invalidate();
    }

    int mProgress = 0;
    /**
     * 设置进度
     */
    public void setProgress(int progress) {
        status = STATUS_DOWNLOAD;
        mProgress = progress;
        if (mProgress == 100) {
            status = STATUS_COMPLETE;
        }
        invalidate();
    }
复制代码
// kotlin 
class DownloadView @JvmOverloads constructor(context: Context,
                                             attrs: AttributeSet? = null,
                                             defStyleAttr: Int = 0)
    : View(context, attrs, defStyleAttr) {
    private var status = STATUS_Prepare
    private var bgColor // 背景色
            = 0
    private var progressColor // 进度条se
            = 0
    private var pauseColor // 暂停
            = 0
    var text: String? = "点击下载"
    private var mTextColor = 0
    var width = 120f
    var height = 50f
    var mProgress = 0

    /**
     * 是否在下载
     * @return
     */
    fun isLoading(): Boolean {
        return if (status == STATUS_downLoad) {
            true
        } else false
    }
    private lateinit var mPaint: Paint
    private lateinit var mTextPaint: Paint

    /**
     * 画笔
     */
    private fun initPaint() {
        // 画笔初始化
        mPaint = Paint()
        mPaint?.apply {
            color = mProgress
            isAntiAlias = true // 消除锯齿
            style = Paint.Style.FILL
        }
        mTextPaint = Paint()
        mTextPaint?.apply {
            color = mTextColor
            isAntiAlias = true // 消除锯齿
            style = Paint.Style.FILL
            textAlign = Paint.Align.CENTER
            textSize = 18f
        }
    }

    /**
     * 初始化
     * @param attrs
     */
    private fun init(attrs: AttributeSet?) {
        context.obtainStyledAttributes(attrs, R.styleable.DownloadView)?.apply {
            bgColor =getColor(R.styleable.DownloadView_bgColor, -0xff3367)
            progressColor = getColor(R.styleable.DownloadView_progressColor, 0x4400CC99)
            pauseColor = getColor(R.styleable.DownloadView_pauseColor, -0xff3367)
            mTextColor = getColor(R.styleable.DownloadView_text, -0x1)
            recycle()
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        width = MeasureSpec.getSize(widthMeasureSpec).toFloat()
        height = MeasureSpec.getSize(heightMeasureSpec).toFloat()
        setMeasuredDimension(MeasureSpec.makeMeasureSpec(width.toInt(), MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(height.toInt(), MeasureSpec.EXACTLY))
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 设置背景 圆角矩形绘制
        mPaint?.color = bgColor
        canvas.drawRoundRect(RectF(0f, 0f, width.toFloat(), height.toFloat()), 100f, 100f, mPaint!!)
        // 根据状态制定绘制
        when (status){
            STATUS_downLoad -> {
                text = "$mProgress%"
                val progressRight = mProgress / 100f * width
                canvas.save()
                // 进度条颜色 并绘制
                mPaint!!.color = progressColor
                // 进度条 裁剪画布
                canvas.clipRect(0f, 0f, progressRight, height.toFloat())
                // 进度条背景
                canvas.drawRoundRect(RectF(0f, 0f, width.toFloat(), height.toFloat()), 100f, 100f, mPaint!!)
                canvas.restore() // 释放资源
            }
            STATUS_complete -> text = "下载完成"
            STATUS_Prepare -> text = "点击下载"
            STATUS_PAUSE -> text = "暂停下载"
            else -> { }
        }
        val fm = mTextPaint?.fontMetrics
        val y = height / 2 + (fm.descent - fm.ascent) / 2 - fm.descent
        canvas.drawText(text!!, (width / 2).toFloat(), y, mTextPaint)
    }

    fun start() {
        if (status == STATUS_Prepare ||
                status == STATUS_PAUSE) {
            status = STATUS_downLoad
        }
    }

    fun pause() {
        if (status == STATUS_downLoad) {
            status = STATUS_PAUSE
        }
        invalidate()
    }


    /**
     * 设置进度
     */
    fun setProgress(progress: Int) {
        status = STATUS_downLoad
        mProgress = progress
        if (mProgress == 100) {
            status = STATUS_complete
        }
        invalidate() // 刷新
    }

    companion object {
        const val STATUS_Prepare = 1 // 准备下载
        const val STATUS_downLoad = 2 // 正在下载
        const val STATUS_PAUSE = 3 // 暂停下载
        const val STATUS_complete = 4 // 完成下载
    }

    init {
        init(attrs)
        initPaint()
    }

复制代码

// xml 属性部分

<declare-styleable name="DownloadView">
        <attr name="progressColor" format="color"></attr>
        <attr name="bgColor" format="color"></attr>
        <attr name="textColor" format="color"></attr>
        <attr name="text" format="string"></attr>
        <attr name="pauseColor" format="color"></attr>
    </declare-styleable>
复制代码

如有问题 沙滩联系 gogogo

猜你喜欢

转载自juejin.im/post/7129776212817707022