1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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
}
}
|