Android自定义带矩形进度框的布局

1.需求

1、需要一个RelativeLayout, 进度条环绕此布局,进度条可以设置宽度,颜色,背景

2、可设置进度起点,方向

3、可设置进度文字提示

先看效果

2.实现

根据需求定义参数和属性,定义四个起点 和 进度条的方向:顺时针和逆时针等

companion object {
        //起点位置
        const val LEFT_TOP = 0
        const val RIGHT_TOP = 1
        const val RIGHT_BOTTOM = 2
        const val LEFT_BOTTOM = 3

        //方向
        const val CLOCKWISE = 0
        const val ANTI_CLOCKWISE = 1
    }

    /**
     * 进度条宽度
     */
    var progressWidth = 0f

    /**
     * 进度条颜色
     */
    var progressColor = Color.GREEN

    /**
     * 进度条背景
     */
    var progressBgColor = Color.TRANSPARENT

    /**
     * 进度条开始点
     */
    var startPoint = LEFT_TOP

    /**
     * 进度条进度方向
     */
    var orientation = CLOCKWISE

    /**
     * 文字颜色
     */
    var textColor = Color.BLACK

    /**
     * 文字大小
     */
    var textSize = 0f

    /**
     * 当前进度
     */
    var currentProgress = 0

添加对应的attr

 <declare-styleable name="RecProgressLayout">

        <attr name="rpl_progress_width" format="dimension" />
        <attr name="rpl_progress_color" format="color|reference" />
        <attr name="rpl_progress_bg_color" format="color|reference" />
        <attr name="rpl_start_point" format="enum">
            <enum name="left_top" value="0" />
            <enum name="right_top" value="1" />
            <enum name="right_bottom" value="2" />
            <enum name="left_bottom" value="3" />
        </attr>
        <attr name="rpl_orientation" format="enum">
            <enum name="clockwise" value="0" />
            <enum name="anti_clockwise" value="1" />
        </attr>
        <attr name="rpl_text_color" format="color|reference" />
        <attr name="rpl_text_size" format="dimension" />
        <attr name="rpl_current_progress" format="integer" />

    </declare-styleable>

然后画进度条,根据进度刷新进度条和文字进度提示,根据不同起点和方向计算进度条的长度和位置,刷新进度即可,详细看源码

3.源码

有很多要优化的地方,在此就不做了,实现功能就行了

class RecProgressLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {

    companion object {
        //起点位置
        const val LEFT_TOP = 0
        const val RIGHT_TOP = 1
        const val RIGHT_BOTTOM = 2
        const val LEFT_BOTTOM = 3

        //方向
        const val CLOCKWISE = 0
        const val ANTI_CLOCKWISE = 1
    }

    /**
     * 进度条宽度
     */
    var progressWidth = 0f

    /**
     * 进度条颜色
     */
    var progressColor = Color.GREEN

    /**
     * 进度条背景
     */
    var progressBgColor = Color.TRANSPARENT

    /**
     * 进度条开始点
     */
    var startPoint = LEFT_TOP

    /**
     * 进度条进度方向
     */
    var orientation = CLOCKWISE

    /**
     * 文字颜色
     */
    var textColor = Color.BLACK

    /**
     * 文字大小
     */
    var textSize = 0f

    /**
     * 当前进度
     */
    var currentProgress = 0

    private var progressBgPaint: Paint
    private var progressPaint: Paint
    var textView: TextView? = null
    var layoutParams: LayoutParams

    init {
        val a = context.obtainStyledAttributes(attrs, R.styleable.RecProgressLayout)
        progressWidth = a.getDimension(R.styleable.RecProgressLayout_rpl_progress_width, 1f)
        progressColor = a.getColor(R.styleable.RecProgressLayout_rpl_progress_color, Color.GREEN)
        progressBgColor =
            a.getColor(R.styleable.RecProgressLayout_rpl_progress_bg_color, Color.TRANSPARENT)
        startPoint = a.getInteger(R.styleable.RecProgressLayout_rpl_start_point, LEFT_TOP)
        orientation = a.getInteger(R.styleable.RecProgressLayout_rpl_orientation, CLOCKWISE)
        textColor = a.getColor(R.styleable.RecProgressLayout_rpl_text_color, Color.BLACK)
        textSize = a.getDimension(R.styleable.RecProgressLayout_rpl_text_size, 0f)
        currentProgress = a.getInteger(R.styleable.RecProgressLayout_rpl_current_progress, 0)
        a.recycle()

        progressBgPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        progressBgPaint.color = progressBgColor
        progressBgPaint.strokeWidth = progressWidth
        progressBgPaint.style = Paint.Style.STROKE

        progressPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        progressPaint.color = progressColor
        progressPaint.strokeWidth = progressWidth
        progressPaint.style = Paint.Style.STROKE

        if (textSize != 0f) {
            textView = TextView(context)
            textView?.setTextColor(textColor)
            textView?.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
        }

        layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)

        setWillNotDraw(false)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        drawProgressBg(canvas)
        drawProgress(canvas)
        if (textView != null)
            drawText()
    }

    fun setProgress(progress: Int) {
        currentProgress = progress
        invalidate()
    }

    /**
     * 绘制进度条背景
     * @param canvas Canvas?
     */
    private fun drawProgressBg(canvas: Canvas?) {
        if (orientation == CLOCKWISE) {
            drawTop(canvas, progressBgPaint, width.toFloat())
            drawRight(canvas, progressBgPaint, height.toFloat())
            drawBottom(canvas, progressBgPaint, 0f)
            drawLeft(canvas, progressBgPaint, 0f)
        } else {
            drawTop(canvas, progressBgPaint, 0f)
            drawRight(canvas, progressBgPaint, 0f)
            drawBottom(canvas, progressBgPaint, width.toFloat())
            drawLeft(canvas, progressBgPaint, height.toFloat())
        }
    }

    /**
     * 绘制进度条
     * @param canvas Canvas?
     */
    private fun drawProgress(canvas: Canvas?) {
        val totalWidth = 2 * (width + height) - 4 * progressWidth
        val progress = totalWidth * (currentProgress / 100.0f)
        when (startPoint) {
            LEFT_TOP -> {
                drawAtLeftTop(canvas, totalWidth, progress)
            }
            LEFT_BOTTOM -> {
                drawAtLeftBottom(canvas, totalWidth, progress)
            }
            RIGHT_TOP -> {
                drawAtRightTop(canvas, totalWidth, progress)
            }
            RIGHT_BOTTOM -> {
                drawAtRightBottom(canvas, totalWidth, progress)
            }
        }
    }

    @SuppressLint("NewApi")
    private fun drawText() {
        removeView(textView)
        val content = "$currentProgress%"
        textView?.text = content
        layoutParams.addRule(CENTER_IN_PARENT)
        textView?.layoutParams = layoutParams
        addView(textView)
    }

    /**
     * 绘制上方边进度条
     * @param canvas Canvas?
     */
    private fun drawTop(canvas: Canvas?, paint: Paint, width: Float) {
        if (orientation == CLOCKWISE) {
            canvas?.drawLine(
                progressWidth,
                progressWidth / 2.0f,
                width,
                progressWidth / 2.0f,
                paint
            )
        } else {
            canvas?.drawLine(
                this.width - progressWidth,
                progressWidth / 2.0f,
                width,
                progressWidth / 2.0f,
                paint
            )
        }
    }

    /**
     * 绘制右边进度条
     * @param canvas Canvas?
     */
    private fun drawRight(canvas: Canvas?, paint: Paint, height: Float) {
        if (orientation == CLOCKWISE) {
            canvas?.drawLine(
                width.toFloat() - progressWidth / 2.0f,
                progressWidth,
                width.toFloat() - progressWidth / 2.0f,
                height,
                paint
            )
        } else {
            canvas?.drawLine(
                width - progressWidth / 2.0f,
                this.height - progressWidth,
                width - progressWidth / 2.0f,
                height,
                paint
            )
        }
    }

    /**
     * 绘制下方进度条
     * @param canvas Canvas?
     */
    private fun drawBottom(canvas: Canvas?, paint: Paint, width: Float) {
        if (orientation == CLOCKWISE) {
            canvas?.drawLine(
                this.width - progressWidth,
                height.toFloat() - progressWidth / 2.0f,
                width,
                height.toFloat() - progressWidth / 2.0f,
                paint
            )
        } else {
            canvas?.drawLine(
                progressWidth,
                height - progressWidth / 2.0f,
                width,
                height - progressWidth / 2.0f,
                paint
            )
        }
    }

    /**
     * 绘制左边进度条
     * @param canvas Canvas?
     */
    private fun drawLeft(canvas: Canvas?, paint: Paint, height: Float) {
        if (orientation == CLOCKWISE) {
            canvas?.drawLine(
                progressWidth / 2.0f,
                this.height - progressWidth,
                progressWidth / 2.0f,
                height,
                paint
            )
        } else {
            canvas?.drawLine(
                progressWidth / 2.0f,
                progressWidth,
                progressWidth / 2.0f,
                height,
                paint
            )
        }
    }

    /**
     * 绘制起点在左上
     * @param canvas Canvas?
     * @param totalWidth Float
     * @param progress Float
     */
    private fun drawAtLeftTop(canvas: Canvas?, totalWidth: Float, progress: Float) {
        if (orientation == CLOCKWISE) {
            if (progress >= width - progressWidth) {
                drawTop(canvas, progressPaint, width.toFloat())
                if (currentProgress >= 50) {
                    drawRight(canvas, progressPaint, height.toFloat())
                    if (progress >= width * 2 + height - 3 * progressWidth) {
                        drawBottom(canvas, progressPaint, 0f)
                        if (currentProgress == 100) {
                            drawLeft(canvas, progressPaint, 0f)
                        } else {
                            drawLeft(canvas, progressPaint, totalWidth - progress)
                        }
                    } else {
                        drawBottom(
                            canvas,
                            progressPaint,
                            2 * width + height - 3 * progressWidth - progress
                        )
                    }
                } else {
                    drawRight(
                        canvas,
                        progressPaint,
                        progress - width + 2 * progressWidth
                    )
                }
            } else {
                drawTop(canvas, progressPaint, progressWidth + progress)
            }
        } else {
            if (progress >= height - progressWidth) {
                drawLeft(canvas, progressPaint, height.toFloat())
                if (currentProgress >= 50) {
                    drawBottom(canvas, progressPaint, height.toFloat())
                    if (progress >= height * 2 + width - 3 * progressWidth) {
                        drawRight(canvas, progressPaint, 0f)
                        if (currentProgress == 100) {
                            drawTop(canvas, progressPaint, 0f)
                        } else {
                            drawTop(canvas, progressPaint, width - (totalWidth - progress))
                        }
                    } else {
                        drawRight(
                            canvas,
                            progressPaint,
                            2 * height + width - (progress + 3 * progressWidth)
                        )
                    }
                } else {
                    drawBottom(
                        canvas,
                        progressPaint,
                        progress + 2 * progressWidth - height
                    )
                }
            } else {
                drawLeft(canvas, progressPaint, progressWidth + progress)
            }
        }
    }

    /**
     * 绘制起点在左下
     * @param canvas Canvas?
     * @param totalWidth Float
     * @param progress Float
     */
    private fun drawAtLeftBottom(canvas: Canvas?, totalWidth: Float, progress: Float) {
        if (orientation == CLOCKWISE) {
            if (progress >= height - progressWidth) {
                drawLeft(canvas, progressPaint, 0f)
                if (currentProgress >= 50) {
                    drawTop(canvas, progressPaint, width.toFloat())
                    if (progress >= height * 2 + width - 3 * progressWidth) {
                        drawRight(canvas, progressPaint, height.toFloat())
                        if (currentProgress == 100) {
                            drawBottom(canvas, progressPaint, 0f)
                        } else {
                            drawBottom(canvas, progressPaint, totalWidth - progress)
                        }
                    } else {
                        drawRight(
                            canvas,
                            progressPaint,
                            progress - 3 * progressWidth - height - width
                        )
                    }
                } else {
                    drawTop(
                        canvas,
                        progressPaint,
                        progress - height + 2 * progressWidth
                    )
                }
            } else {
                drawLeft(canvas, progressPaint, height - progress)
            }
        } else {
            if (progress >= width - progressWidth) {
                drawBottom(canvas, progressPaint, width.toFloat())
                if (currentProgress >= 50) {
                    drawRight(canvas, progressPaint, 0f)
                    if (progress >= width * 2 + height - 3 * progressWidth) {
                        drawTop(canvas, progressPaint, 0f)
                        if (currentProgress == 100) {
                            drawLeft(canvas, progressPaint, height.toFloat())
                        } else {
                            drawLeft(
                                canvas,
                                progressPaint,
                                height - (totalWidth - progress)
                            )
                        }
                    } else {
                        drawTop(
                            canvas,
                            progressPaint,
                            2 * width + height - (progress + 3 * progressWidth)
                        )
                    }
                } else {
                    drawRight(
                        canvas,
                        progressPaint,
                        height + width - (progress + 2 * progressWidth)
                    )
                }
            } else {
                drawBottom(canvas, progressPaint, progress)
            }
        }
    }

    /**
     * 绘制起点在右上
     * @param canvas Canvas?
     * @param totalWidth Float
     * @param progress Float
     */
    private fun drawAtRightTop(canvas: Canvas?, totalWidth: Float, progress: Float) {
        if (orientation == CLOCKWISE) {
            if (progress >= height - progressWidth) {
                drawRight(canvas, progressPaint, height.toFloat())
                if (currentProgress >= 50) {
                    drawBottom(canvas, progressPaint, 0f)
                    if (progress >= height * 2 + width - 3 * progressWidth) {
                        drawLeft(canvas, progressPaint, 0f)
                        if (currentProgress == 100) {
                            drawTop(canvas, progressPaint, width.toFloat())
                        } else {
                            drawTop(canvas, progressPaint, width - (totalWidth - progress))
                        }
                    } else {
                        drawLeft(
                            canvas,
                            progressPaint,
                            2 * height + width - 3 * progressWidth - progress
                        )
                    }
                } else {
                    drawBottom(
                        canvas,
                        progressPaint,
                        width + height - progress - 2 * progressWidth
                    )
                }
            } else {
                drawRight(canvas, progressPaint, progressWidth + progress)
            }
        } else {
            if (progress >= width - progressWidth) {
                drawTop(canvas, progressPaint, 0f)
                if (currentProgress >= 50) {
                    drawLeft(canvas, progressPaint, height.toFloat())
                    if (progress >= width * 2 + height - 3 * progressWidth) {
                        drawBottom(canvas, progressPaint, width.toFloat())
                        if (currentProgress == 100) {
                            drawRight(canvas, progressPaint, 0f)
                        } else {
                            drawRight(canvas, progressPaint, totalWidth - progress)
                        }
                    } else {
                        drawBottom(
                            canvas,
                            progressPaint,
                            progress + 3 * progressWidth - width - height
                        )
                    }
                } else {
                    drawLeft(
                        canvas,
                        progressPaint,
                        progress + 2 * progressWidth - width
                    )
                }
            } else {
                drawTop(canvas, progressPaint, width - progressWidth - progress)
            }
        }
    }

    /**
     * 绘制起点在左上
     * @param canvas Canvas?
     * @param totalWidth Float
     * @param progress Float
     */
    private fun drawAtRightBottom(canvas: Canvas?, totalWidth: Float, progress: Float) {
        if (orientation == CLOCKWISE) {
            if (progress >= width - progressWidth) {
                drawBottom(canvas, progressPaint, 0f)
                if (currentProgress >= 50) {
                    drawLeft(canvas, progressPaint, 0f)
                    if (progress >= width * 2 + height - 3 * progressWidth) {
                        drawTop(canvas, progressPaint, width.toFloat())
                        if (currentProgress == 100) {
                            drawRight(canvas, progressPaint, height.toFloat())
                        } else {
                            drawRight(canvas, progressPaint, totalWidth - progress)
                        }
                    } else {
                        drawTop(
                            canvas,
                            progressPaint,
                            3 * progressWidth + progress - width - height
                        )
                    }
                } else {
                    drawLeft(
                        canvas,
                        progressPaint,
                        width + height - progress - 2 * progressWidth
                    )
                }
            } else {
                drawBottom(canvas, progressPaint, width - progressWidth - progress)
            }
        } else {
            if (progress >= height - progressWidth) {
                drawRight(canvas, progressPaint, 0f)
                if (currentProgress >= 50) {
                    drawTop(canvas, progressPaint, 0f)
                    if (progress >= height * 2 + width - 3 * progressWidth) {
                        drawLeft(canvas, progressPaint, height.toFloat())
                        if (currentProgress == 100) {
                            drawBottom(canvas, progressPaint, width.toFloat())
                        } else {
                            drawBottom(canvas, progressPaint, width - (totalWidth - progress))
                        }
                    } else {
                        drawLeft(
                            canvas,
                            progressPaint,
                            progress + 3 * progressWidth - width - height
                        )
                    }
                } else {
                    drawTop(
                        canvas,
                        progressPaint,
                        height + width - progress - 2 * progressWidth
                    )
                }
            } else {
                drawRight(canvas, progressPaint, height - progress - progressWidth)
            }
        }
    }
}

4.使用

<com.xx.xxx.widget.RecProgressLayout
    android:id="@+id/rec_layout"
    android:layout_width="200dp"
    android:layout_height="300dp"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:rpl_orientation="clockwise"
    app:rpl_start_point="left_top"
    app:rpl_progress_width="8dp"
    app:rpl_current_progress="0"
    app:rpl_progress_color="@color/progress_color"
    app:rpl_progress_bg_color="@color/transparent_color">

    <ImageView
        android:id="@+id/iv_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="8dp"
        android:scaleType="centerCrop"
        android:src="@mipmap/ic_logo"
        android:visibility="visible"/>
</com.xx.xxx.widget.RecProgressLayout>

代码中直接 调用 binding.recProgressLayout.setProgress(进度1-100)就可以了

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值