Skip to content

Instantly share code, notes, and snippets.

@YohannesTz
Created June 8, 2024 18:00
Show Gist options
  • Save YohannesTz/1a4a1946b620c6ee11d9e7fa08e92a2b to your computer and use it in GitHub Desktop.
Save YohannesTz/1a4a1946b620c6ee11d9e7fa08e92a2b to your computer and use it in GitHub Desktop.
RatingView for android that has an emoji effect
package com.github.yohannestz.visionedu.view.customview
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
class RatingView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private var sliderValue: Float = 0.2f
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
// Setter for sliderValue
fun setSliderValue(value: Float) {
sliderValue = value.coerceIn(0.2f, 1f)
invalidate() // Redraw the view
}
@SuppressLint("DrawAllocation")
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val width = width.toFloat()
val height = height.toFloat()
// Center and radius
val centerX = width / 2
val centerY = height / 2
val radius = width.coerceAtMost(height) / 3
// Dynamic color based on sliderValue
val startColor = Color.parseColor("#fc4e03")
val endColor = Color.parseColor("#ffb803")
val dynamicColor = lerpColor(startColor, endColor, sliderValue)
// Draw the face
paint.color = dynamicColor
paint.style = Paint.Style.FILL
canvas.drawCircle(centerX, centerY, radius, paint)
if (sliderValue < 0.5) {
// Draw eyes
paint.color = Color.BLACK
paint.style = Paint.Style.FILL
canvas.drawCircle(centerX - 40f, centerY - 40f, 8f, paint)
canvas.drawCircle(centerX + 40f, centerY - 40f, 8f, paint)
} else {
val tiltAngle = (sliderValue - 0.5f) * 0.2f
// Draw V-shaped eyes
drawVShape(canvas, centerX - 40f, centerY - 40f, tiltAngle)
drawVShape(canvas, centerX + 40f, centerY - 40f, tiltAngle)
// Draw blush
paint.style = Paint.Style.FILL
paint.shader = createRadialGradient(centerX - 50f, centerY + 10f, 20f, startColor, endColor)
canvas.drawCircle(centerX - 50f, centerY + 10f, 20f, paint)
paint.shader = createRadialGradient(centerX + 50f, centerY + 10f, 20f, startColor, endColor)
canvas.drawCircle(centerX + 50f, centerY + 10f, 20f, paint)
paint.shader = null
}
// Draw mouth
paint.color = Color.BLACK
paint.style = Paint.Style.STROKE
paint.strokeWidth = 4f
val rectF = RectF(centerX - 30f, centerY - 5f, centerX + 30f, centerY - 5f + sliderValue * 50f)
canvas.drawArc(rectF, 0f, 180f, false, paint)
}
private fun createRadialGradient(centerX: Float, centerY: Float, radius: Float, startColor: Int, endColor: Int): RadialGradient {
return RadialGradient(
centerX, centerY, radius,
intArrayOf(Color.parseColor("#fc4e03"), lerpColor(startColor, endColor, sliderValue)),
null, Shader.TileMode.CLAMP
)
}
private fun drawVShape(canvas: Canvas, x: Float, y: Float, tiltAngle: Float) {
val lineLength = 15f
paint.color = Color.BLACK
paint.style = Paint.Style.STROKE
paint.strokeWidth = 10f
val xOffset = lineLength * tiltAngle
val yOffset = lineLength * tiltAngle
canvas.drawLine(x - lineLength + xOffset, y + lineLength + yOffset, x, y, paint)
canvas.drawLine(x, y, x + lineLength + xOffset, y + lineLength + yOffset, paint)
}
private fun lerpColor(startColor: Int, endColor: Int, fraction: Float): Int {
val startR = Color.red(startColor)
val startG = Color.green(startColor)
val startB = Color.blue(startColor)
val startA = Color.alpha(startColor)
val endR = Color.red(endColor)
val endG = Color.green(endColor)
val endB = Color.blue(endColor)
val endA = Color.alpha(endColor)
val r = (startR + fraction * (endR - startR)).toInt()
val g = (startG + fraction * (endG - startG)).toInt()
val b = (startB + fraction * (endB - startB)).toInt()
val a = (startA + fraction * (endA - startA)).toInt()
return Color.argb(a, r, g, b)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment