horizontal expand/collapse

This commit is contained in:
InsanusMokrassar 2020-12-15 13:25:01 +06:00
parent 1890608cb3
commit 830b7aee56
2 changed files with 90 additions and 22 deletions

View File

@ -2,6 +2,10 @@
## 0.4.13
* `Common`
* `Android`
* Add expand/collapse functionality for horizontal expand/collapse
## 0.4.12
* `Coroutines`

View File

@ -5,56 +5,108 @@ import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.Transformation
private fun View.performExpand(
duration: Long = 500,
targetWidth: Int = ViewGroup.LayoutParams.MATCH_PARENT,
targetHeight: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
onMeasured: View.() -> Unit,
onPerformAnimation: View.(interpolatedTime: Float, t: Transformation?) -> Unit
) {
measure(targetWidth, targetHeight)
onMeasured()
visibility = View.VISIBLE
val a: Animation = object : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
super.applyTransformation(interpolatedTime, t)
onPerformAnimation(interpolatedTime, t)
requestLayout()
}
override fun willChangeBounds(): Boolean = true
}
a.duration = duration
startAnimation(a)
}
private fun View.performCollapse(
duration: Long = 500,
onPerformAnimation: View.(interpolatedTime: Float, t: Transformation?) -> Unit
) {
val a: Animation = object : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
if (interpolatedTime == 1f) {
gone()
} else {
onPerformAnimation(interpolatedTime, t)
requestLayout()
}
}
override fun willChangeBounds(): Boolean {
return true
}
}
a.duration = duration
startAnimation(a)
}
@PreviewFeature
fun View.expand(
duration: Long = 500,
targetWidth: Int = ViewGroup.LayoutParams.MATCH_PARENT,
targetHeight: Int = ViewGroup.LayoutParams.WRAP_CONTENT
) {
measure(targetWidth, targetHeight)
val measuredHeight: Int = measuredHeight
layoutParams.height = 0
visibility = View.VISIBLE
val a: Animation = object : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
super.applyTransformation(interpolatedTime, t)
var measuredHeight = 0
performExpand(
duration,
targetWidth,
targetHeight,
{
measuredHeight = this.measuredHeight
}
) { interpolatedTime, _ ->
layoutParams.height = if (interpolatedTime == 1f) targetHeight else (measuredHeight * interpolatedTime).toInt()
requestLayout()
}
override fun willChangeBounds(): Boolean {
return true
}
}
a.duration = duration
startAnimation(a)
@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
val a: Animation = object : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
if (interpolatedTime == 1f) {
visibility = View.GONE
} else {
performCollapse(duration) { interpolatedTime, _ ->
layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt()
requestLayout()
}
}
override fun willChangeBounds(): Boolean {
return true
@PreviewFeature
fun View.collapseHorizontally(duration: Long = 500) {
val initialWidth: Int = measuredWidth
performCollapse(duration) { interpolatedTime, _ ->
layoutParams.width = initialWidth - (initialWidth * interpolatedTime).toInt()
}
}
a.duration = duration
startAnimation(a)
}
@PreviewFeature
inline val View.isCollapsed
get() = visibility == View.GONE
@ -74,3 +126,15 @@ fun View.toggleExpandState(duration: Long = 500): Boolean = if (isCollapsed) {
collapse(duration)
false
}
/**
* @return true in case of expanding
*/
@PreviewFeature
fun View.toggleExpandHorizontallyState(duration: Long = 500): Boolean = if (isCollapsed) {
expandHorizontally(duration)
true
} else {
collapseHorizontally(duration)
false
}