Created
October 3, 2018 17:50
-
-
Save gpeal/14d9644387631f96fb7e2dec3d56e052 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.yourapp | |
import android.support.annotation.IdRes | |
import android.support.v4.app.Fragment | |
import android.view.View | |
import android.view.ViewGroup | |
import kotlin.properties.ReadOnlyProperty | |
import kotlin.reflect.KProperty | |
private object UNINITIALIZED | |
@Suppress("unused") | |
fun <T : View, F> F.bindView(@IdRes resId: Int) where F : Fragment, F : ViewBindingOwner = FragmentViewBinder<T, F>(resId) | |
class FragmentViewBinder<T : View, F>(@IdRes private val resId: Int) : ReadOnlyProperty<F, T> where F : Fragment, F : ViewBindingOwner { | |
private var view: Any? = UNINITIALIZED | |
override fun getValue(thisRef: F, property: KProperty<*>): T { | |
if (view == UNINITIALIZED) { | |
view = thisRef.view?.findViewById(resId) ?: throw IllegalStateException("Unable to find view for ${thisRef.resources.getResourceName(resId)}") | |
assertCorrectType(thisRef) | |
thisRef.addViewBinder(this) | |
} | |
@Suppress("UNCHECKED_CAST") | |
return view as T | |
} | |
fun clear() { | |
view = UNINITIALIZED | |
} | |
private fun assertCorrectType(thisRef: Fragment) { | |
@Suppress("UNCHECKED_CAST") | |
if (view as? T == null) { | |
val resName = thisRef.resources.getResourceName(resId) | |
throw IllegalStateException("Incorrect type for $resName") | |
} | |
} | |
} | |
/** | |
* Contains helpers to get butterknife-like support for Kotlin Fragments. | |
* | |
* To use, create a property like: | |
* private val myView: TextView by bindView(R.id.your_id) | |
*/ | |
fun <T : View> bindView(@IdRes resId: Int) = object : ReadOnlyProperty<ViewGroup, T> { | |
private lateinit var view: Any | |
override fun getValue(thisRef: ViewGroup, property: KProperty<*>): T { | |
if (!::view.isInitialized) { | |
view = thisRef.findViewById(resId) ?: throw IllegalStateException("Unable to find view for ${thisRef.resources.getResourceName(resId)}") | |
assertCorrectType(thisRef) | |
} | |
@Suppress("UNCHECKED_CAST") | |
return view as T | |
} | |
private fun assertCorrectType(thisRef: ViewGroup) { | |
@Suppress("UNCHECKED_CAST") | |
if (view as? T == null) { | |
val resName = thisRef.resources.getResourceName(resId) | |
throw IllegalStateException("Incorrect type for $resName") | |
} | |
} | |
} | |
/** | |
* A Fragment should implement this if they want to use the bindView delegate. | |
* | |
* The Fragment should keep track of a list of ViewBinders as they are added then call clear on each of them in onDestroyView. | |
*/ | |
interface ViewBindingOwner { | |
fun addViewBinder(binder: FragmentViewBinder<*, *>) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment