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