看到这个效果,可能会想到完全自定义一个控件,其实我们在系统Seekbar的基础上,将progressDrawable中progress背景设为透明后,叠加绘制试听状态下的进度区域即可
class PlayerSeekBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
defStyleRes: Int = 0,
) : SeekBar(context, attrs, defStyleAttr, defStyleRes) {
private var tryPlayable = true
private var tryPlayableStartPos = 10
private var tryPlayableEndPos = 60
private val normalProgressDrawable: Drawable? =
context.getDrawable(R.drawable.bg_player_seekbar)
private val fakeProgressDrawable: Drawable? =
context.getDrawable(R.drawable.bg_player_seekbar_fake)
private val tryPlayableBgPaint: Paint by lazy {
Paint().apply {
isAntiAlias = true
style = Paint.Style.FILL_AND_STROKE
color = context.getColor(R.color.player_try_playable_progress_color)
}
}
private val tryPlayableProgressPaint by lazy {
Paint().apply {
isAntiAlias = true
style = Paint.Style.FILL_AND_STROKE
color = context.getColor(R.color.player_track_color)
}
}
private var playSeekBarChangeListener: OnPlaySeekBarChangeListener? = null
init {
setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
playSeekBarChangeListener?.onProgressChanged(seekBar, progress, fromUser)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
playSeekBarChangeListener?.onStartTrackingTouch(seekBar)
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
playSeekBarChangeListener?.onStopTrackingTouch(seekBar)
if (isOverTryPlayableAre()) {
playSeekBarChangeListener?.onOverTryPlayableArea()
}
}
})
}
private fun isOverTryPlayableAre(): Boolean {
return tryPlayable && (progress > tryPlayableEndPos || progress < tryPlayableStartPos)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (tryPlayable) {
val tryPlayableProgress =
progress.coerceAtLeast(tryPlayableStartPos).coerceAtMost(tryPlayableEndPos)
// 试听区域背景
drawTryPlayableRect(canvas, tryPlayableBgPaint, tryPlayableStartPos, tryPlayableEndPos)
// 试听区域进度
drawTryPlayableRect(
canvas,
tryPlayableProgressPaint,
tryPlayableStartPos,
tryPlayableProgress
)
}
}
private fun drawTryPlayableRect(canvas: Canvas?, paint: Paint, startPos: Int, endPos: Int) {
val percent = (endPos - startPos) * 1.0F / (max - min)
val left =
paddingLeft + (startPos - min) * 1.0F / (max - min) * (width - paddingLeft - paddingRight)
val top = paddingTop.toFloat()
val right = left + (width - paddingLeft - paddingRight) * percent
val bottom = (height - paddingBottom).toFloat()
canvas?.drawRect(left, top, right, bottom, paint)
}
fun setTryPlayable(tryPlayable: Boolean) {
this.tryPlayable = tryPlayable
progressDrawable = if (tryPlayable) {
fakeProgressDrawable
} else {
normalProgressDrawable
}
invalidate()
}
fun setTryPlayProgress(tryPlayableStartPos: Int, tryPlayableEndPos: Int) {
this.tryPlayableStartPos = tryPlayableStartPos
this.tryPlayableEndPos = tryPlayableEndPos
invalidate()
}
fun setOnPlaySeekBarChangeListener(listener: OnPlaySeekBarChangeListener) {
this.playSeekBarChangeListener = listener
}
interface OnPlaySeekBarChangeListener : OnSeekBarChangeListener {
// 超出试听区域
fun onOverTryPlayableArea()
}
}