aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt')
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt105
1 files changed, 105 insertions, 0 deletions
diff --git a/core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt
new file mode 100644
index 0000000..6994ca2
--- /dev/null
+++ b/core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt
@@ -0,0 +1,105 @@
+package ca.allanwang.kau.ui.views
+
+import android.animation.ValueAnimator
+import android.view.View
+import ca.allanwang.kau.utils.*
+import java.lang.ref.WeakReference
+
+/**
+ * Created by Allan Wang on 2017-08-03.
+ *
+ * Delegation class for collapsible views
+ *
+ * Views that implement this MUST call [initCollapsible] before using any of the methods
+ * Additionally, you will need to call [getCollapsibleDimension] and use the response for
+ * [View.setMeasuredDimension] during [View.onMeasure]
+ * (That method is protected so we cannot access it here)
+ *
+ * With reference to <a href="https://github.com/cachapa/ExpandableLayout">ExpandableLayout</a>
+ */
+interface CollapsibleView {
+ var expansion: Float
+ val state: Int
+ val expanded: Boolean
+ fun initCollapsible(view: View)
+ fun resetCollapsibleAnimation()
+ fun getCollapsibleDimension(): Pair<Int, Int>
+ fun toggleExpansion()
+ fun toggleExpansion(animate: Boolean)
+ fun expand()
+ fun expand(animate: Boolean)
+ fun collapse()
+ fun collapse(animate: Boolean)
+ fun setExpanded(expand: Boolean)
+ fun setExpanded(expand: Boolean, animate: Boolean)
+}
+
+class CollapsibleViewDelegate : CollapsibleView {
+
+ private lateinit var viewRef: WeakReference<View>
+ private val view
+ get() = viewRef.get()
+ private var animator: ValueAnimator? = null
+
+ override var expansion = 0f
+ set(value) {
+ if (value == field) return
+ var v = value
+ if (v > 1) v = 1f
+ else if (v < 0) v = 0f
+ stateHolder =
+ if (v == 0f) KAU_COLLAPSED
+ else if (v == 1f) KAU_EXPANDED
+ else if (v - field < 0) KAU_COLLAPSING
+ else KAU_EXPANDING
+ field = v
+ view?.goneIf(state == KAU_COLLAPSED)
+ view?.requestLayout()
+ }
+
+ private var stateHolder = KAU_COLLAPSED
+ override val state
+ get() = stateHolder
+ override val expanded
+ get() = stateHolder == KAU_EXPANDED || stateHolder == KAU_EXPANDING
+
+ override fun initCollapsible(view: View) {
+ this.viewRef = WeakReference(view)
+ }
+
+ override fun resetCollapsibleAnimation() {
+ animator?.cancel()
+ animator = null
+ if (stateHolder == KAU_COLLAPSING) stateHolder = KAU_COLLAPSED
+ else if (stateHolder == KAU_EXPANDING) stateHolder = KAU_EXPANDED
+ }
+
+ override fun getCollapsibleDimension(): Pair<Int, Int> {
+ val v = view ?: return Pair(0, 0)
+ val size = v.measuredHeight
+ v.goneIf(expansion == 0f && size == 0)
+ return Pair(v.measuredWidth, Math.round(size * expansion))
+ }
+
+ private fun animateSize(target: Float) {
+ resetCollapsibleAnimation()
+ animator = ValueAnimator.ofFloat(expansion, target).apply {
+ addUpdateListener { expansion = it.animatedValue as Float }
+ start()
+ }
+ }
+
+ override fun toggleExpansion() = toggleExpansion(true)
+ override fun toggleExpansion(animate: Boolean) = setExpanded(!expanded, animate)
+ override fun expand() = expand(true)
+ override fun expand(animate: Boolean) = setExpanded(true, animate)
+ override fun collapse() = collapse(true)
+ override fun collapse(animate: Boolean) = setExpanded(false, animate)
+ override fun setExpanded(expand: Boolean) = setExpanded(expand, true)
+ override fun setExpanded(expand: Boolean, animate: Boolean) {
+ if (expand == expanded) return //state already matches
+ val target = if (expand) 1f else 0f
+ if (animate) animateSize(target) else expansion = target
+ }
+
+} \ No newline at end of file