Skip to content

Instantly share code, notes, and snippets.

@dilrajsingh1997
Created June 1, 2022 09:52
Show Gist options
  • Save dilrajsingh1997/4af260b223c584a71fcf5f95f05711bc to your computer and use it in GitHub Desktop.
Save dilrajsingh1997/4af260b223c584a71fcf5f95f05711bc to your computer and use it in GitHub Desktop.
fun getPathCanvasObject() = CanvasPath(
path = Path().apply {
heartPath(Size(120f, 120f))
},
)
fun getTextCanvasObject(text: String = "hi") =
CanvasText(text) {
color = android.graphics.Color.WHITE
isAntiAlias = true
textSize = 48f
typeface =
android.graphics.Typeface.create(android.graphics.Typeface.DEFAULT,
android.graphics.Typeface.BOLD)
}
class SinWaveAnimationSpec(
val durationMillis: Int = AnimationConstants.DefaultDurationMillis,
val delay: Int = 0,
val easing: Easing = FastOutSlowInEasing,
val multiplier: Int = 100,
) : DurationBasedAnimationSpec<Float> {
override fun <V : AnimationVector> vectorize(converter: TwoWayConverter<Float, V>): VectorizedDurationBasedAnimationSpec<V> =
object : VectorizedDurationBasedAnimationSpec<V> {
private val anim = VectorizedFloatAnimationSpec<V>(
SinWaveSpec(durationMillis, delayMillis, easing, multiplier)
)
override fun getValueFromNanos(
playTimeNanos: Long,
initialValue: V,
targetValue: V,
initialVelocity: V,
): V {
return anim.getValueFromNanos(playTimeNanos,
initialValue,
targetValue,
initialVelocity)
}
override fun getVelocityFromNanos(
playTimeNanos: Long,
initialValue: V,
targetValue: V,
initialVelocity: V,
): V {
return anim.getVelocityFromNanos(playTimeNanos,
initialValue,
targetValue,
initialVelocity)
}
override val delayMillis: Int
get() = this@SinWaveAnimationSpec.delay
override val durationMillis: Int
get() = this@SinWaveAnimationSpec.durationMillis
}
override fun equals(other: Any?): Boolean =
if (other is SinWaveAnimationSpec) {
other.durationMillis == this.durationMillis &&
other.delay == this.delay &&
other.easing == this.easing
} else {
false
}
override fun hashCode(): Int {
return (durationMillis * 31 + easing.hashCode()) * 31 + delay
}
}
class SinWaveSpec(
val duration: Int = AnimationConstants.DefaultDurationMillis,
val delay: Int = 0,
private val easing: Easing = FastOutSlowInEasing,
private val multiplier: Int,
) : FloatAnimationSpec {
override fun getValueFromNanos(
playTimeNanos: Long,
initialValue: Float,
targetValue: Float,
initialVelocity: Float,
): Float {
val playTimeMillis = playTimeNanos / 1_000_000L
val clampedPlayTime = clampPlayTime(playTimeMillis)
val rawFraction = if (duration == 0) 1f else clampedPlayTime / duration.toFloat()
val fraction = easing.transform(rawFraction.coerceIn(0f, 1f))
return initialValue + multiplier * (sin(fraction * 2 * Math.PI).toFloat())
}
private fun clampPlayTime(playTime: Long): Long {
return (playTime - delay).coerceIn(0, duration.toLong())
}
override fun getDurationNanos(
initialValue: Float,
targetValue: Float,
initialVelocity: Float,
): Long {
return (delay + duration) * 1_000_000L
}
override fun getVelocityFromNanos(
playTimeNanos: Long,
initialValue: Float,
targetValue: Float,
initialVelocity: Float,
): Float {
return 0f
}
}
val SineEasing = Easing { fraction -> sin(fraction * 2 * Math.PI / 4).toFloat() }
val InverseCosineEasing = Easing { fraction -> 1 - cos(fraction * 2 * Math.PI / 4).toFloat() }
fun Path.heartPath(size: Size): Path {
//the logic is taken from StackOverFlow [answer](https://stackoverflow.com/a/41251829/5348665)and converted into extension function
val width: Float = size.width
val height: Float = size.height
moveTo(width / 2, height / 5)
cubicTo(
5 * width / 14, 0f,
0f, height / 15,
width / 28, 2 * height / 5
)
cubicTo(
width / 14, 2 * height / 3,
3 * width / 7, 5 * height / 6,
width / 2, height
)
cubicTo(
4 * width / 7, 5 * height / 6,
13 * width / 14, 2 * height / 3,
27 * width / 28, 2 * height / 5
)
cubicTo(
width, height / 15,
9 * width / 14, 0f,
width / 2, height / 5
)
return this
}
fun <T> List<T>.safeGet(index: Int?): T? {
return if (index != null && index >= 0 && index <= lastIndex) {
this[index]
} else {
null
}
}
fun <T> MutableList<T>.safeSet(index: Int?, update: (value: T) -> T): Boolean {
return if (index != null && index >= 0 && index <= lastIndex) {
this[index] = update(this[index])
true
} else {
false
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment