Skip to content

Instantly share code, notes, and snippets.

@NinoDLC
Created August 26, 2022 13:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NinoDLC/ace212124f7b33b67ae1e0488c49fdfe to your computer and use it in GitHub Desktop.
Save NinoDLC/ace212124f7b33b67ae1e0488c49fdfe to your computer and use it in GitHub Desktop.
ViewBinding delegates
@file:Suppress("unused")
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import androidx.viewbinding.ViewBinding
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
/** Activity binding delegate, may be used since onCreate up to onDestroy (inclusive) */
inline fun <T : ViewBinding> AppCompatActivity.viewBinding(
crossinline factory: (LayoutInflater) -> T,
) = lazy(LazyThreadSafetyMode.NONE) {
factory(layoutInflater)
}
/** Fragment binding delegate, may be used since onViewCreated up to onDestroyView (inclusive) */
inline fun <T : ViewBinding> Fragment.viewBinding(
crossinline factory: (View) -> T,
): ReadOnlyProperty<Fragment, T> = object : ReadOnlyProperty<Fragment, T>, DefaultLifecycleObserver {
private var binding: T? = null
private val viewLifecycleOwnerLiveDataObserver = Observer<LifecycleOwner?> {
it?.lifecycle?.addObserver(object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
binding = null
}
})
}
init {
lifecycle.addObserver(this)
}
override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
val capturedBinding = binding
if (capturedBinding != null) {
return capturedBinding
}
if (!viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
throw IllegalStateException("Should not attempt to get bindings when Fragment views are destroyed.")
}
return factory(thisRef.requireView()).also { this.binding = it }
}
override fun onCreate(owner: LifecycleOwner) {
viewLifecycleOwnerLiveData.observeForever(viewLifecycleOwnerLiveDataObserver)
}
override fun onDestroy(owner: LifecycleOwner) {
viewLifecycleOwnerLiveData.removeObserver(viewLifecycleOwnerLiveDataObserver)
}
}
/** Binding delegate for DialogFragments implementing onCreateDialog (like Activities, they don't
* have a separate view lifecycle), may be used since onCreateDialog up to onDestroy (inclusive) */
inline fun <T : ViewBinding> DialogFragment.viewBinding(
crossinline factory: (LayoutInflater) -> T,
) = lazy(LazyThreadSafetyMode.NONE) {
factory(layoutInflater)
}
/** Not really a delegate, just a small helper for RecyclerView.ViewHolders */
inline fun <T : ViewBinding> ViewGroup.viewBinding(
factory: (LayoutInflater, ViewGroup, Boolean) -> T,
) = factory(LayoutInflater.from(context), this, false)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment