85 lines
2.7 KiB
Kotlin
85 lines
2.7 KiB
Kotlin
package relax.offline.music.view
|
|
|
|
import android.animation.ValueAnimator
|
|
import android.content.Context
|
|
import android.graphics.Canvas
|
|
import android.graphics.Color
|
|
import android.graphics.Paint
|
|
import android.util.AttributeSet
|
|
import android.util.TypedValue
|
|
import android.view.View
|
|
|
|
class MusicBarsView @JvmOverloads constructor(
|
|
context: Context,
|
|
attrs: AttributeSet? = null,
|
|
defStyleAttr: Int = 0
|
|
) : View(context, attrs, defStyleAttr) {
|
|
|
|
// 用于绘制柱子的 Paint 对象
|
|
private val barPaint = Paint().apply {
|
|
color = Color.parseColor("#FF80F988")
|
|
style = Paint.Style.FILL
|
|
}
|
|
|
|
// 每个柱子的宽度
|
|
private val barWidth = dpToPx(context,4f)
|
|
// 柱子之间的间距
|
|
private val barSpacing = dpToPx(context,2f)
|
|
// 柱子的圆角半径
|
|
private val cornerRadius = dpToPx(context,16f)
|
|
|
|
// 保存每个柱子高度的列表
|
|
private val barHeights = mutableListOf<Float>()
|
|
|
|
// 保存每个柱子动画的列表
|
|
private val animators = mutableListOf<ValueAnimator>()
|
|
|
|
init {
|
|
// 初始化柱子的高度并启动动画
|
|
for (i in 0 until 3) {
|
|
barHeights.add(0f)
|
|
startAnimation(i)
|
|
}
|
|
}
|
|
|
|
// 启动动画
|
|
private fun startAnimation(index: Int) {
|
|
val animator = ValueAnimator.ofFloat(0f, 1f).apply {
|
|
duration = 500 // 动画持续时间为 500 毫秒
|
|
repeatCount = ValueAnimator.INFINITE // 无限重复动画
|
|
repeatMode = ValueAnimator.REVERSE // 反向重复
|
|
addUpdateListener { animation ->
|
|
// 更新柱子的高度
|
|
barHeights[index] = (animation.animatedValue as Float) * height
|
|
invalidate() // 重绘 View
|
|
}
|
|
startDelay = index * 200L // 设置动画的开始延迟时间
|
|
}
|
|
animators.add(animator)
|
|
animator.start() // 启动动画
|
|
}
|
|
|
|
override fun onDraw(canvas: Canvas) {
|
|
super.onDraw(canvas)
|
|
|
|
val barCount = barHeights.size
|
|
val totalWidth = barCount * barWidth + (barCount - 1) * barSpacing
|
|
val startX = (width - totalWidth) / 2
|
|
|
|
// 绘制每个柱子
|
|
barHeights.forEachIndexed { index, barHeight ->
|
|
val left = startX + index * (barWidth + barSpacing)
|
|
val top = height - barHeight
|
|
val right = left + barWidth
|
|
val bottom = height.toFloat()
|
|
|
|
canvas.drawRoundRect(left, top, right, bottom, cornerRadius, cornerRadius, barPaint)
|
|
}
|
|
}
|
|
|
|
fun dpToPx(context: Context, dp: Float): Float {
|
|
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.resources.displayMetrics)
|
|
}
|
|
}
|
|
|