diff --git a/CHANGELOG.md b/CHANGELOG.md index d0cc0f37d24..8b371ee67d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 0.4.13 +* `Common` + * `Android` + * Add expand/collapse functionality for horizontal expand/collapse + ## 0.4.12 * `Coroutines` diff --git a/common/src/main/kotlin/dev/inmo/micro_utils/common/ExpandCollapse.kt b/common/src/main/kotlin/dev/inmo/micro_utils/common/ExpandCollapse.kt index 4fba2b56349..33e8a8322ed 100644 --- a/common/src/main/kotlin/dev/inmo/micro_utils/common/ExpandCollapse.kt +++ b/common/src/main/kotlin/dev/inmo/micro_utils/common/ExpandCollapse.kt @@ -5,23 +5,44 @@ import android.view.ViewGroup import android.view.animation.Animation import android.view.animation.Transformation -@PreviewFeature -fun View.expand( +private fun View.performExpand( duration: Long = 500, targetWidth: Int = ViewGroup.LayoutParams.MATCH_PARENT, - targetHeight: Int = ViewGroup.LayoutParams.WRAP_CONTENT + targetHeight: Int = ViewGroup.LayoutParams.WRAP_CONTENT, + onMeasured: View.() -> Unit, + onPerformAnimation: View.(interpolatedTime: Float, t: Transformation?) -> Unit ) { measure(targetWidth, targetHeight) - val measuredHeight: Int = measuredHeight - layoutParams.height = 0 + onMeasured() visibility = View.VISIBLE val a: Animation = object : Animation() { override fun applyTransformation(interpolatedTime: Float, t: Transformation?) { super.applyTransformation(interpolatedTime, t) - layoutParams.height = if (interpolatedTime == 1f) targetHeight else (measuredHeight * interpolatedTime).toInt() + 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 } @@ -32,27 +53,58 @@ fun View.expand( startAnimation(a) } +@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 - val a: Animation = object : Animation() { - override fun applyTransformation(interpolatedTime: Float, t: Transformation?) { - if (interpolatedTime == 1f) { - visibility = View.GONE - } else { - layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt() - requestLayout() - } - } - - override fun willChangeBounds(): Boolean { - return true - } + performCollapse(duration) { interpolatedTime, _ -> + layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt() } +} - a.duration = duration - - startAnimation(a) +@PreviewFeature +fun View.collapseHorizontally(duration: Long = 500) { + val initialWidth: Int = measuredWidth + performCollapse(duration) { interpolatedTime, _ -> + layoutParams.width = initialWidth - (initialWidth * interpolatedTime).toInt() + } } @PreviewFeature @@ -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 +}