diff --git a/app/src/main/res/layout/layout_drag_icon_view.xml b/app/src/main/res/layout/layout_drag_icon_view.xml index 3b93b9a..bfa3d34 100644 --- a/app/src/main/res/layout/layout_drag_icon_view.xml +++ b/app/src/main/res/layout/layout_drag_icon_view.xml @@ -1,9 +1,9 @@ - - - + --> + + diff --git a/core/architecture/src/main/java/com/ama/core/architecture/widget/CircleProgressBar.kt b/core/architecture/src/main/java/com/ama/core/architecture/widget/CircleProgressBar.kt new file mode 100644 index 0000000..192f38d --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/widget/CircleProgressBar.kt @@ -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() + } +} \ No newline at end of file diff --git a/core/architecture/src/main/res/values/attrs.xml b/core/architecture/src/main/res/values/attrs.xml index 94a1e41..5669c59 100644 --- a/core/architecture/src/main/res/values/attrs.xml +++ b/core/architecture/src/main/res/values/attrs.xml @@ -24,5 +24,19 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/architecture/src/main/res/values/colors.xml b/core/architecture/src/main/res/values/colors.xml index 3a86657..6866be3 100644 --- a/core/architecture/src/main/res/values/colors.xml +++ b/core/architecture/src/main/res/values/colors.xml @@ -57,4 +57,8 @@ #ff00ff09 + #FF00FF5E + #99000000 + + \ No newline at end of file