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())
}
}