@@ -25,27 +25,29 @@ import android.view.ViewGroup
25
25
import androidx.activity.ComponentActivity
26
26
import androidx.databinding.ViewDataBinding
27
27
import androidx.fragment.app.Fragment
28
- import androidx.lifecycle.Lifecycle
29
- import androidx.lifecycle.LifecycleObserver
30
- import androidx.lifecycle.OnLifecycleEvent
28
+ import androidx.lifecycle.*
31
29
import androidx.viewbinding.ViewBinding
32
30
import com.google.android.material.navigation.NavigationView
33
31
import com.google.android.material.tabs.TabLayout
34
32
import kotlin.properties.ReadOnlyProperty
35
33
import kotlin.reflect.KProperty
36
34
35
+ private var View .binding: Any?
36
+ get() = getTag(- 1 )
37
+ set(value) = setTag(- 1 , value)
37
38
38
39
inline fun <reified VB : ViewBinding > ComponentActivity.binding () = lazy {
39
- inflateBinding<VB >(layoutInflater).also {
40
- setContentView(it .root)
41
- if (this is ViewDataBinding ) lifecycleOwner = this @binding
40
+ inflateBinding<VB >(layoutInflater).also { binding ->
41
+ setContentView(binding .root)
42
+ if (binding is ViewDataBinding ) binding. lifecycleOwner = this
42
43
}
43
44
}
44
45
45
- inline fun <reified VB : ViewBinding > Fragment.binding () = FragmentBindingDelegate <VB > { requireView().bind() }
46
+ inline fun <reified VB : ViewBinding > Fragment.binding () =
47
+ FragmentBindingDelegate <VB > { requireView().getBinding() }
46
48
47
49
inline fun <reified VB : ViewBinding > Fragment.binding (method : Method ) =
48
- FragmentBindingDelegate <VB > { if (method == Method .BIND ) requireView().bind () else inflateBinding(layoutInflater) }
50
+ FragmentBindingDelegate <VB > { if (method == Method .BIND ) requireView().getBinding () else inflateBinding(layoutInflater) }
49
51
50
52
inline fun <reified VB : ViewBinding > Dialog.binding () = lazy {
51
53
inflateBinding<VB >(layoutInflater).also { setContentView(it.root) }
@@ -58,18 +60,34 @@ inline fun <reified VB : ViewBinding> ViewGroup.binding(attachToParent: Boolean
58
60
inline fun <reified VB : ViewBinding > ViewGroup.inflate () =
59
61
inflateBinding<VB >(LayoutInflater .from(context), this , true )
60
62
61
- inline fun <reified VB : ViewBinding > TabLayout.Tab.setCustomView (onBindView : VB .() -> Unit ) {
62
- customView = inflateBinding<VB >(LayoutInflater .from(parent!! .context)).apply (onBindView).root
63
+ inline fun <reified VB : ViewBinding > TabLayout.Tab.setCustomView (block : VB .() -> Unit ) {
64
+ inflateBinding<VB >(LayoutInflater .from(parent!! .context)).apply (block).let { binding ->
65
+ customView = binding.root
66
+ customView?.tag = binding
67
+ }
63
68
}
64
69
65
- inline fun <reified VB : ViewBinding > TabLayout.Tab.bindCustomView (onBindView : VB .() -> Unit ) =
66
- customView?.bind<VB >()?.run (onBindView)
70
+ inline fun <reified VB : ViewBinding > TabLayout.doOnCustomTabSelected (
71
+ crossinline onTabUnselected : VB .(TabLayout .Tab ) -> Unit = {},
72
+ crossinline onTabReselected : VB .(TabLayout .Tab ) -> Unit = {},
73
+ crossinline onTabSelected : VB .(TabLayout .Tab ) -> Unit = {},
74
+ ) =
75
+ addOnTabSelectedListener(object : TabLayout .OnTabSelectedListener {
76
+ override fun onTabSelected (tab : TabLayout .Tab ) {
77
+ tab.customView?.getBinding<VB >()?.onTabSelected(tab)
78
+ }
79
+
80
+ override fun onTabUnselected (tab : TabLayout .Tab ) {
81
+ tab.customView?.getBinding<VB >()?.onTabUnselected(tab)
82
+ }
67
83
68
- inline fun <reified VB : ViewBinding > TabLayout.Tab.bindCustomView (bind : (View ) -> VB , onBindView : VB .() -> Unit ) =
69
- customView?.let { bind(it) }?.run (onBindView)
84
+ override fun onTabReselected (tab : TabLayout .Tab ) {
85
+ tab.customView?.getBinding<VB >()?.onTabReselected(tab)
86
+ }
87
+ })
70
88
71
- inline fun <reified VB : ViewBinding > NavigationView.setHeaderView (index : Int = 0, onBindView : VB .() -> Unit ) =
72
- getHeaderView(index)?.bind <VB >()?.run (onBindView )
89
+ inline fun <reified VB : ViewBinding > NavigationView.setHeaderView (index : Int = 0, block : VB .() -> Unit ) =
90
+ getHeaderView(index)?.getBinding <VB >()?.run (block )
73
91
74
92
inline fun <reified VB : ViewBinding > inflateBinding (layoutInflater : LayoutInflater ) =
75
93
VB ::class .java.getMethod(" inflate" , LayoutInflater ::class .java).invoke(null , layoutInflater) as VB
@@ -83,16 +101,15 @@ inline fun <reified VB : ViewBinding> inflateBinding(
83
101
VB ::class .java.getMethod(" inflate" , LayoutInflater ::class .java, ViewGroup ::class .java, Boolean ::class .java)
84
102
.invoke(null , layoutInflater, parent, attachToParent) as VB
85
103
86
- inline fun <reified VB : ViewBinding > View.bind () =
87
- VB ::class .java.getMethod(" bind" , View ::class .java).invoke(null , this ) as VB
104
+ inline fun <reified VB : ViewBinding > View.getBinding () = getBinding(VB ::class .java)
88
105
89
- inline fun Fragment. doOnDestroyView (crossinline block : () -> Unit ) =
90
- viewLifecycleOwner.lifecycle.addObserver( object : LifecycleObserver {
91
- @OnLifecycleEvent( Lifecycle . Event . ON_DESTROY )
92
- fun onDestroyView () {
93
- block.invoke()
94
- }
95
- })
106
+ @Suppress( " UNCHECKED_CAST " )
107
+ fun < VB : ViewBinding > View. getBinding ( clazz : Class < VB >) =
108
+ if (binding != null ) {
109
+ binding as VB
110
+ } else {
111
+ (clazz.getMethod( " bind " , View :: class .java).invoke( null , this ) as VB ). also { binding = it }
112
+ }
96
113
97
114
enum class Method { BIND , INFLATE }
98
115
@@ -106,16 +123,18 @@ class FragmentBindingDelegate<VB : ViewBinding>(private val block: () -> VB) : R
106
123
override fun getValue (thisRef : Fragment , property : KProperty <* >): VB {
107
124
if (binding == null ) {
108
125
binding = try {
109
- block().also {
110
- if (it is ViewDataBinding ) it .lifecycleOwner = thisRef.viewLifecycleOwner
126
+ block().also { binding ->
127
+ if (binding is ViewDataBinding ) binding .lifecycleOwner = thisRef.viewLifecycleOwner
111
128
}
112
129
} catch (e: IllegalStateException ) {
113
130
throw IllegalStateException (" The binding property has been destroyed." )
114
131
}
115
- thisRef.doOnDestroyView {
116
- if (thisRef is BindingLifecycleOwner ) thisRef.onDestroyViewBinding(binding!! )
117
- binding = null
118
- }
132
+ thisRef.viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
133
+ override fun onDestroy (owner : LifecycleOwner ) {
134
+ if (thisRef is BindingLifecycleOwner ) thisRef.onDestroyViewBinding(binding!! )
135
+ binding = null
136
+ }
137
+ })
119
138
}
120
139
return binding!!
121
140
}
0 commit comments