draw image by seekbar ratio

class CompareImageView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {

    fun setFrontDrawable(resource: Drawable?) {
        this.setFrontBitmap(resource?.toBitmap(resource.intrinsicWidth, resource.intrinsicHeight))
    }

    fun setFrontBitmap(bitmap: Bitmap?) {
        this.bitmapFront = bitmap
        invalidate()
    }

    fun getFrontImageBitmap():Bitmap? {
        return this.bitmapFront
    }

    fun setBackDrawable(resource: Drawable?) {
        this.setBackBitmap(resource?.toBitmap(resource.intrinsicWidth, resource.intrinsicHeight))
    }

    fun setBackBitmap(backBitmap: Bitmap?) {
        if(null != backBitmap) {
            val backgroundBitmap = getRoundedCornerBitmap(backBitmap, cornerRadius.toFloat())
            this.background = BitmapDrawable(context.resources, backgroundBitmap)
        } else {
            this.setBackgroundResource(R.drawable.transparent)
        }
        invalidate()
    }

    fun clearImages() {
        this.bitmapFront  = null
        this.background = null
        invalidate()
    }

    private val valueAnimator = ValueAnimator.ofFloat(0f, 0.618f)

    fun startAnimationProgress() {
        stopAnimationProgress()
        valueAnimator.repeatCount = 0
        valueAnimator.duration = 1600

        valueAnimator.addUpdateListener {
            val ratio = it.animatedValue as Float
            binding.seekbar.progress = (binding.seekbar.max * ratio).toInt()
        }
        valueAnimator.start()
    }

    private fun stopAnimationProgress() {
        valueAnimator?.cancel()
    }

    private var cornerRadius: Int = SizeUtil.dp2px(8f)

    fun setRadius(cornerRadius:Int) {
        this.cornerRadius = cornerRadius
    }

    private fun getRoundedCornerBitmap(bitmap: Bitmap, radius: Float): Bitmap {
        val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(output)
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        val rect = Rect(0, 0, bitmap.width, bitmap.height)
        val rectF = RectF(rect)
        val shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
        paint.shader = shader
        canvas.drawRoundRect(rectF, radius, radius, paint)
        return output
    }

    private val binding get() = _binding!!

    private var _binding: ViewCompareImageViewBinding? = null

    private var bitmapFront: Bitmap? = null
    private var ratio: Float = 0.618f

    private val path = Path()

    init {
        _binding = ViewCompareImageViewBinding.inflate(LayoutInflater.from(context), this, true)
    }

    override fun onFinishInflate() {
        super.onFinishInflate()
        initSeekbar()
    }

    private fun initSeekbar() {
        val seekBar = binding.seekbar
        val seekBarMax = 100f

        seekBar.max = seekBarMax.toInt()
        seekBar.progress = (ratio*seekBarMax).toInt()

        seekBar.setOnClickListener {  }
        seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                val ratio = progress / seekBarMax
                this@CompareImageView.ratio = ratio

                invalidate()
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {
            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {
            }
        })
    }

    @SuppressLint("DrawAllocation")
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        refreshSeekView(canvas)
    }

    private fun refreshSeekView(canvas: Canvas) {
        if(bitmapFront?.isRecycled == true) {
            return
        }
        path.reset()
        path.addRoundRect(0f, 0f, width.toFloat(), height.toFloat(), cornerRadius.toFloat(), cornerRadius.toFloat(), Path.Direction.CW)
        canvas.clipPath(path)

        val currentX = width * ratio

        bitmapFront?.let { it ->
            val rect = Rect((it.width * ratio).toInt(), 0, it.width, it.height)
            val rectDest = Rect(currentX.toInt(), 0, width, height)
            canvas.drawBitmap(it, rect, rectDest, null)
        }
        binding.seekIndicator.translationX = currentX - binding.seekIndicator.width/2
    }
}