MicroUtils/common/src/androidMain/kotlin/dev/inmo/micro_utils/common/ExpandCollapse.kt

141 lines
3.7 KiB
Kotlin
Raw Normal View History

2020-11-23 11:39:17 +00:00
package dev.inmo.micro_utils.common
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.Transformation
2020-12-15 07:25:01 +00:00
private fun View.performExpand(
2020-11-23 11:39:17 +00:00
duration: Long = 500,
targetWidth: Int = ViewGroup.LayoutParams.MATCH_PARENT,
2020-12-15 07:25:01 +00:00
targetHeight: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
onMeasured: View.() -> Unit,
onPerformAnimation: View.(interpolatedTime: Float, t: Transformation?) -> Unit
2020-11-23 11:39:17 +00:00
) {
measure(targetWidth, targetHeight)
2020-12-15 07:25:01 +00:00
onMeasured()
2020-12-15 07:26:34 +00:00
show()
2020-11-23 11:39:17 +00:00
val a: Animation = object : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
super.applyTransformation(interpolatedTime, t)
2020-12-15 07:25:01 +00:00
onPerformAnimation(interpolatedTime, t)
2020-11-23 11:39:17 +00:00
requestLayout()
}
2020-12-15 07:25:01 +00:00
override fun willChangeBounds(): Boolean = true
2020-11-23 11:39:17 +00:00
}
a.duration = duration
startAnimation(a)
}
2020-12-15 07:25:01 +00:00
private fun View.performCollapse(
duration: Long = 500,
onPerformAnimation: View.(interpolatedTime: Float, t: Transformation?) -> Unit
) {
2020-11-23 11:39:17 +00:00
val a: Animation = object : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
if (interpolatedTime == 1f) {
2020-12-15 07:25:01 +00:00
gone()
2020-11-23 11:39:17 +00:00
} else {
2020-12-15 07:25:01 +00:00
onPerformAnimation(interpolatedTime, t)
2020-11-23 11:39:17 +00:00
requestLayout()
}
}
override fun willChangeBounds(): Boolean {
return true
}
}
a.duration = duration
startAnimation(a)
}
2020-12-15 07:25:01 +00:00
@PreviewFeature
fun View.expand(
duration: Long = 500,
targetWidth: Int = ViewGroup.LayoutParams.MATCH_PARENT,
targetHeight: Int = ViewGroup.LayoutParams.WRAP_CONTENT
) {
var measuredHeight = 0
performExpand(
duration,
targetWidth,
targetHeight,
{
measuredHeight = this.measuredHeight
}
) { interpolatedTime, _ ->
layoutParams.height = if (interpolatedTime == 1f) targetHeight else (measuredHeight * interpolatedTime).toInt()
}
}
@PreviewFeature
fun View.expandHorizontally(
duration: Long = 500,
targetWidth: Int = ViewGroup.LayoutParams.MATCH_PARENT,
targetHeight: Int = ViewGroup.LayoutParams.WRAP_CONTENT
) {
var measuredWidth = 0
performExpand(
duration,
targetWidth,
targetHeight,
{
measuredWidth = this.measuredWidth
}
) { interpolatedTime, _ ->
layoutParams.width = if (interpolatedTime == 1f) targetWidth else (measuredWidth * interpolatedTime).toInt()
}
}
@PreviewFeature
fun View.collapse(duration: Long = 500) {
val initialHeight: Int = measuredHeight
performCollapse(duration) { interpolatedTime, _ ->
layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt()
}
}
@PreviewFeature
fun View.collapseHorizontally(duration: Long = 500) {
val initialWidth: Int = measuredWidth
performCollapse(duration) { interpolatedTime, _ ->
layoutParams.width = initialWidth - (initialWidth * interpolatedTime).toInt()
}
}
2020-11-23 11:39:17 +00:00
@PreviewFeature
inline val View.isCollapsed
get() = visibility == View.GONE
@PreviewFeature
inline val View.isExpanded
get() = !isCollapsed
/**
* @return true in case of expanding
*/
@PreviewFeature
fun View.toggleExpandState(duration: Long = 500): Boolean = if (isCollapsed) {
expand(duration)
true
} else {
collapse(duration)
false
}
2020-12-15 07:25:01 +00:00
/**
* @return true in case of expanding
*/
@PreviewFeature
fun View.toggleExpandHorizontallyState(duration: Long = 500): Boolean = if (isCollapsed) {
expandHorizontally(duration)
true
} else {
collapseHorizontally(duration)
false
}