优化圆形progressbar

This commit is contained in:
renhaoting 2025-11-25 14:15:47 +08:00
parent e1d1dbb2b0
commit c4855e93cf
4 changed files with 231 additions and 4 deletions

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<com.ama.core.common.widget.DragLayout <com.ama.core.common.widget.DragLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:orientation="vertical"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingVertical="7dp" android:paddingVertical="7dp"
@ -40,7 +40,7 @@
/> />
</LinearLayout> </LinearLayout>
<FrameLayout <!--<FrameLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<ProgressBar <ProgressBar
@ -56,7 +56,19 @@
android:layout_gravity="center" android:layout_gravity="center"
android:paddingVertical="7dp" android:paddingVertical="7dp"
/> />
</FrameLayout> </FrameLayout>-->
<com.ama.core.architecture.widget.CircleProgressBar
android:id="@+id/progress_bar"
android:layout_width="50dp"
android:layout_height="50dp"
app:progressColor="@color/progress_green"
app:backgroundColor="@color/progress_background"
app:progressWidth="2dp"
app:centerIcon="@mipmap/home_envelope"
app:currentProgress="35"
app:maxProgress="100"
/>
</LinearLayout> </LinearLayout>
</com.ama.core.common.widget.DragLayout> </com.ama.core.common.widget.DragLayout>

View File

@ -0,0 +1,197 @@
package com.ama.core.architecture.widget
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.ama.core.architecture.R
import com.ama.core.common.util.dp
class CircleProgressBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.FILL
strokeCap = Paint.Cap.ROUND
}
private val progressPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.STROKE
strokeCap = Paint.Cap.ROUND
}
private var progressWidth = 0f
private var progressColor = 0
private var backgroundColor = 0
private var centerIcon: Bitmap? = null
private var maxProgress = 100
private var currentProgress = 0
private var startAngle = -90f
private val rectF = RectF()
private var viewSize = 0
init {
initAttributes(attrs, defStyleAttr)
}
private fun initAttributes(attrs: AttributeSet?, defStyleAttr: Int) {
val typedArray = context.obtainStyledAttributes(
attrs, R.styleable.CircleProgressBar, defStyleAttr, 0
)
try {
// 获取自定义属性
progressColor = typedArray.getColor(
R.styleable.CircleProgressBar_progressColor,
ContextCompat.getColor(context, R.color.progress_green)
)
backgroundColor = typedArray.getColor(
R.styleable.CircleProgressBar_backgroundColor,
ContextCompat.getColor(context, R.color.progress_background)
)
progressWidth = typedArray.getDimension(
R.styleable.CircleProgressBar_progressWidth,
dpToPx(2f)
)
val iconRes = typedArray.getResourceId(R.styleable.CircleProgressBar_centerIcon, 0)
if (iconRes != 0) {
setCenterIcon(iconRes)
}
maxProgress = typedArray.getInt(R.styleable.CircleProgressBar_maxProgress, 100)
currentProgress = typedArray.getInt(R.styleable.CircleProgressBar_currentProgress, 0)
startAngle = typedArray.getInt(R.styleable.CircleProgressBar_startAngle, -90).toFloat()
} finally {
typedArray.recycle()
}
setupPaints()
}
private fun setupPaints() {
backgroundPaint.color = backgroundColor
backgroundPaint.strokeWidth = progressWidth
progressPaint.color = progressColor
progressPaint.strokeWidth = progressWidth
// 设置半透明效果,模仿图片中的绿色弧线
progressPaint.alpha = 180
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = MeasureSpec.getSize(heightMeasureSpec)
viewSize = minOf(width, height)
setMeasuredDimension(viewSize, viewSize)
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
val padding = progressWidth / 2
rectF.set(
padding,
padding,
w - padding,
h - padding
)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// 绘制背景圆环
canvas.drawArc(rectF, 0f, 360f, false, backgroundPaint)
// 绘制进度弧线
if (currentProgress > 0) {
val sweepAngle = (currentProgress.toFloat() / maxProgress) * 360f
canvas.drawArc(rectF, startAngle, sweepAngle, false, progressPaint)
}
// 绘制中心图标
centerIcon?.let { icon ->
drawCenterIcon(canvas, icon)
}
}
private fun drawCenterIcon(canvas: Canvas, icon: Bitmap) {
val centerX = width / 2f
val centerY = height / 2f
val iconWidth = icon.width.toFloat()
val iconHeight = icon.height.toFloat()
val iconBorderMargin = 12.dp
val scale: Float = if (iconWidth > iconHeight) {
(width - iconBorderMargin) / iconWidth
} else {
(height - iconBorderMargin) / iconHeight
}
val scaledWidth = iconWidth * scale
val scaledHeight = iconHeight * scale
val left = centerX - scaledWidth / 2
val top = centerY - scaledHeight / 2
val right = centerX + scaledWidth / 2
val bottom = centerY + scaledHeight / 2
val dstRect = RectF(left, top, right, bottom)
canvas.drawBitmap(icon, null, dstRect, null)
}
fun setProgress(progress: Int) {
this.currentProgress = progress.coerceIn(0, maxProgress)
invalidate()
}
fun setCenterIcon(@DrawableRes iconRes: Int) {
centerIcon = BitmapFactory.decodeResource(resources, iconRes)
invalidate()
}
fun setProgressColor(color: Int) {
progressColor = color
progressPaint.color = color
invalidate()
}
fun getProgress(): Int = currentProgress
fun getMaxProgress(): Int = maxProgress
fun setMaxProgress(max: Int) {
maxProgress = max
if (currentProgress > maxProgress) {
currentProgress = maxProgress
}
invalidate()
}
private fun dpToPx(dp: Float): Float {
return dp * resources.displayMetrics.density
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
centerIcon?.recycle()
}
}

View File

@ -24,5 +24,19 @@
<attr name="rightButtonSpacing" format="dimension"/> <attr name="rightButtonSpacing" format="dimension"/>
</declare-styleable> </declare-styleable>
<declare-styleable name="CircleProgressBar" tools:ignore="ResourceName">
<!-- 进度条颜色 -->
<attr name="progressColor" format="color|reference" />
<attr name="backgroundColor" format="color|reference" />
<attr name="progressWidth" format="dimension" />
<!-- 中间图标 -->
<attr name="centerIcon" format="reference" />
<!-- 进度相关 -->
<attr name="maxProgress" format="integer" />
<attr name="currentProgress" format="integer" />
<attr name="startAngle" format="integer" />
</declare-styleable>
</resources> </resources>

View File

@ -57,4 +57,8 @@
<color name="green_09">#ff00ff09</color> <color name="green_09">#ff00ff09</color>
<color name="progress_green">#FF00FF5E</color>
<color name="progress_background">#99000000</color>
</resources> </resources>