Android自定义一个带背景的圆环形进度条(Kotlin)

devtools/2024/12/22 9:24:46/

前言

在Android开发过程中,难免遇到一些复杂的UI组件需要我们自定义

当然使用系统原生组件拼凑也能完成,但是UI复杂度增加了不说,在更新UI状态的时候还不好管理,最重要的是复用的价值不大,上述的操作很容易引增加码冗余度和阅读难度,为此自定义UI成了一个非常不错的选择。

实现一个带进度条的播放按钮,类似于QQ音乐底部控住组件中的播放按钮。

1.ProgressBar组件

ProgressBar是Android开发中用于显示进度的一个UI组件。它通常用于向用户展示某个操作的进度情况,比如文件下载、数据加载等场景。ProgressBar可以以不同的形式展现,常见的有圆形进度条和水平进度条。

主要属性

  • max:进度条的最大值,默认为100。
  • progress:当前进度值。
  • progressDrawable:自定义进度条的Drawable。
  • indeterminate:是否设置为不确定模式,不确定模式的进度条会不断循环动画,而不会停止在一个特定的进度。
  • indeterminateDrawable:自定义不确定模式进度条的Drawable。
  • secondaryProgress:次要进度值,可以用于显示中间进度,比如缓冲进度。

使用场景

  • 下载文件时显示下载进度。
  • 加载数据时显示加载进度。
  • 视频播放时显示缓冲进度。
<ProgressBar  android:id="@+id/progressBar"  style="?android:attr/progressBarStyleHorizontal"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:max="100"  android:progress="50" />

2.自定义组件

继承View,在onDraw中使用Canvas绘制

背景

使用drawBitmap绘制背景

canvas.drawBitmap(it, null, rectF, null)

圆环

drawCircle绘制圆,其中Paint的style设置为STROKE可以绘制环形

strokeWidth就是圆环的半径

private val backgroundPaint = Paint()backgroundPaint.apply {color = backgroundColorstrokeWidth = 10fstyle = Paint.Style.STROKEisAntiAlias = false
}canvas.drawCircle(w, h, r, backgroundPaint)

进度条

drawArc实现环形进度条的绘制

rectF是整个环形的内切正方形坐标,这个正方形坐标需要和背景所在的圆环对上,否则可能出现进度条和背景对不上的问题

private val progressPaint = Paint()progressPaint.apply {color = progressColorstrokeWidth = 10fstyle = Paint.Style.STROKEisAntiAlias = false
}canvas.drawArc(rectF, 270f, progress.toFloat() / max.toFloat() * 360f, false, progressPaint)

 完整代码

class CircleBar : View {private val backgroundPaint = Paint()private val progressPaint = Paint()private var max = 100private var progress = 0private var backgroundColor: Int = Color.WHITEprivate var progressColor: Int = Color.BLACKprivate var backgroundBitmap: Bitmap? = nullprivate val rectF = RectF()private val offset = 5fconstructor(context: Context) : super(context)constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {init(context, attributeSet)}constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context,attributeSet,defStyleAttr) {init(context, attributeSet)}private fun init(context: Context, attributeSet: AttributeSet) {val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.CircleBar)max = typedArray.getInteger(R.styleable.CircleBar_max, 100)progress = typedArray.getInteger(R.styleable.CircleBar_progress, 0)backgroundColor = typedArray.getColor(R.styleable.CircleBar_backgroundColor, Color.WHITE)progressColor = typedArray.getColor(R.styleable.CircleBar_progressColor, Color.BLACK)val background = typedArray.getDrawable(R.styleable.CircleBar_background)if (background != null) {backgroundBitmap = (background as BitmapDrawable).bitmap}typedArray.recycle()backgroundPaint.apply {color = backgroundColorstrokeWidth = 10fstyle = Paint.Style.STROKEisAntiAlias = false}progressPaint.apply {color = progressColorstrokeWidth = 10fstyle = Paint.Style.STROKEisAntiAlias = false}}override fun onDraw(canvas: Canvas) {super.onDraw(canvas)val w = width / 2fval h = height / 2fval r = w - offsetrectF.set(offset, h - r, w + r, h + r)backgroundBitmap?.let { canvas.drawBitmap(it, null, rectF, null) }canvas.drawCircle(w, h, r, backgroundPaint)canvas.drawArc(rectF, 270f, progress.toFloat() / max.toFloat() * 360f, false, progressPaint)}fun setMax(max: Int) {this.max = maxinvalidate()}fun setProgress(progress: Int) {this.progress = progressinvalidate()}fun getMax(): Int {return max}}

组件主题样式

<declare-styleable name="CircleBar"><attr name="max" format="integer" /><attr name="progress" format="integer" /><attr name="backgroundColor" format="color" /><attr name="progressColor" format="color" /><attr name="background" format="reference" />
</declare-styleable>


http://www.ppmy.cn/devtools/101923.html

相关文章

Oracle字符串聚合函数LISTAGG

在Oracle 19c中&#xff0c;LISTAGG函数是一个非常有用的字符串聚合函数&#xff0c;它可以将来自多个行的值连接成一个单独的字符串。这个函数特别适用于将分组内的多个值合并为一个逗号分隔&#xff08;或其他分隔符&#xff09;的字符串。 LISTAGG函数的基本语法如下&#…

LeetCode 3133.数组最后一个元素的最小值:位运算+双指针

【LetMeFly】3133.数组最后一个元素的最小值&#xff1a;位运算双指针 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-array-end/ 给你两个整数 n 和 x 。你需要构造一个长度为 n 的 正整数 数组 nums &#xff0c;对于所有 0 < i < n - 1 &#xff0…

网络游戏运营

游戏运营是将一款游戏平台推入市场&#xff0c;并通过一系列的策略和行动&#xff0c;使玩家从接触、认识到最终成为忠实玩家的过程。这一过程涵盖了多个方面&#xff0c;包括前期准备、上线运营、活动策划、数据分析、渠道合作以及用户维护等。以下是对游戏运营的详细解析&…

用ChatGPT精确营销:如何让AI深度理解并推广你的产品

在现代商业中,人工智能(AI)正迅速成为企业成功的关键因素之一。ChatGPT作为一种强大的语言模型,不仅能回答问题,还能通过深度理解和互动,帮助企业精准推广产品。然而,如何让ChatGPT真正了解并有效地推广你的产品,是许多使用者面临的挑战。在本文中,我们将探讨如何通过…

debian/ubuntu 通过串口连接WiFi

修改 /etc/wpa_supplicant.conf&#xff0c;如果没有这个文件就创建文件 vi /etc/wpa_supplicant.conf设置wifi信息 network{ssid"这里是你的wifi账号"psk"这里是你的wifi密码" }连接wifi killall wpa_supplicant wpa_supplicant -i wlan0 -c /etc/wpa_…

SQLite 插入数据并返回自增ID

要插入数据并返回自增ID&#xff0c;我们可以使用SQLite的last_insert_rowid()函数。这个函数返回了最后一次插入操作的自增ID。 下面我们通过一个示例来演示如何插入数据并返回自增ID。 首先&#xff0c;创建一个表来存储学生信息&#xff1a; CREATE TABLE students (id I…

【研究生论文】—— 综述怎么写

怎么写综述 “综述”指的是对某一特定主题或领域h的文献、研究、进展等进行系统性回顾和总结的一种文章类型。很多时候我们需要知道的不是综述是什么&#xff0c;而是综述不是什么&#xff0c;综述不是单纯的查询报告&#xff0c;综述需要在自己的查询结果上面提出自己的看法和…

5个常见问答 | 1+X证书《大数据应用开发(Python)》

1、 1X大数据应用开发&#xff08;Python&#xff09;哪些人群可以考&#xff1f; 全日制在读的中高职学校、应用型本科、本科层次职业教育试点学校院校的学生&#xff0c;有意向从事与证书相关岗位的社会人士都可考取该证书。 2、1X大数据应用开发&#xff08;Python&am…