【Android】通过Drawable实现圆形进度框效果

Drawable实现方式的优势
  • 不需要定义帧动画
  • 不需要使用ProgressBar控件
  • 直接通过ImageView.setImageDrawable一行代码就能实现进度框效果
实现代码
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import kotlin.math.min

class LoadingDrawable : BaseDrawable() {

    private val frameCount = 8
    private val frameTime = 200L
    private val startTime = System.currentTimeMillis()

    private val colorList = listOf(
        Color.parseColor("#FFC1B2FF"),
        Color.parseColor("#F2FFB2F3"),
        Color.parseColor("#D9C1B2FF"),
        Color.parseColor("#CCFFB2F3"),
        Color.parseColor("#B3C1B2FF"),
        Color.parseColor("#8CFFB2F3"),
        Color.parseColor("#66C1B2FF"),
        Color.parseColor("#4DFFB2F3")
    )

    private val drawArgs = object {
        var frameIndex = 0
        var colorIndex = 0
        var isLongIndicator = true
        var radius = 0f
        var cornerRadius = 0f
        var cx = 0f
        var cy = 0f
        var startX = 0f
        var endX = 0f
        var startY = 0f
        var endY = 0f
        var rotation = 0f
    }

    init {
        paint.style = Paint.Style.FILL_AND_STROKE
        paint.isAntiAlias = true
    }

    override fun onBoundsChange(bounds: Rect) {
        super.onBoundsChange(bounds)
        invalidateSelf()
    }

    override fun draw(canvas: Canvas) {
        val dt = System.currentTimeMillis() - startTime
        drawArgs.frameIndex = (dt / frameTime % frameCount).toInt()
        for (i in 0 until 8) {
            computeDrawArgs(i)
            paint.color = colorList[drawArgs.colorIndex]
            canvas.save()
            canvas.rotate(-drawArgs.rotation, drawArgs.cx, drawArgs.cy)
            canvas.drawRoundRect(drawArgs.startX, drawArgs.startY, drawArgs.endX, drawArgs.endY, drawArgs.radius, drawArgs.radius, paint)
            canvas.restore()
        }
        invalidateSelf()
    }

    private fun computeDrawArgs(indicatorIndex: Int) {
        drawArgs.colorIndex = (drawArgs.frameIndex + indicatorIndex) % frameCount
        drawArgs.isLongIndicator = indicatorIndex % 2 == 0
        drawArgs.radius = min(bounds.width(), bounds.height()) * 0.6f
        drawArgs.cx = bounds.centerX().toFloat()
        drawArgs.cy = bounds.centerY().toFloat()
        drawArgs.startX = drawArgs.cx + 8f / 18f * drawArgs.radius
        if (drawArgs.isLongIndicator) {
            drawArgs.endX = drawArgs.startX + 10f / 18f * drawArgs.radius
        } else {
            drawArgs.endX = drawArgs.startX + 5f / 18f * drawArgs.radius
        }
        drawArgs.startY = drawArgs.cy - 1f / 18f * drawArgs.radius
        drawArgs.endY = drawArgs.cy + 1f / 18f * drawArgs.radius
        drawArgs.cornerRadius = 1f / 18f * drawArgs.radius
        drawArgs.rotation = 360f / 8 * indicatorIndex
    }
}
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView

class LoadingView : AppCompatImageView {

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)
    constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
        setImageDrawable(LoadingDrawable())
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值