Skip to content

Commit

Permalink
Merge pull request #23 from Rere-kt/feature/detach-attach-holders
Browse files Browse the repository at this point in the history
ViewBinder refactoring. Added onDetachedFromWindow & onAttachedToWind…
  • Loading branch information
dionep authored Feb 16, 2021
2 parents 63f4d11 + 25cd166 commit 7cfdea7
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ open class MultiBindingAdapter(
)

override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) =
getBinder(position).bindViewHolder(viewHolder, items[position], position)
getBinder(position).bindViewHolder(
viewHolder = viewHolder as RekuklerViewHolder<*, *>,
position = position,
item = items[position]
)

private fun getBinder(position: Int): ViewBinder<*, *> {
val item = items[position]
Expand All @@ -49,6 +53,16 @@ open class MultiBindingAdapter(
)
}

override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
(holder as RekuklerViewHolder<*, *>).onDetachedFromWindow()
super.onViewDetachedFromWindow(holder)
}

override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
(holder as RekuklerViewHolder<*, *>).onAttachedToWindow()
super.onViewAttachedToWindow(holder)
}

override fun getItemCount() = items.size

/**
Expand Down
69 changes: 56 additions & 13 deletions rekukler/src/main/java/com/rerekt/rekukler/ViewBinder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,81 @@ class ViewBinder<Type: Any, Binding: ViewBinding> (
val isForItem: (item: Any) -> Boolean,
val areItemsSame: (Type, Type) -> Boolean,
val areContentsSame: (Type, Type) -> Boolean,
private val holderBinder: Holder<Type, Binding>.(Type) -> Unit
private val holderBinder: HolderBinder<Type, Binding>.(Type) -> Unit
) {

fun createViewHolder(parent: ViewGroup): RecyclerView.ViewHolder {
fun createViewHolder(parent: ViewGroup): RekuklerViewHolder<Type, Binding> {
val itemView = LayoutInflater.from(parent.context).inflate(layoutResId, parent, false)
return object : RecyclerView.ViewHolder(itemView) {}
return RekuklerViewHolder(
itemView = itemView,
binder = binder,
holderBinder = holderBinder
)
}

@Suppress("UNCHECKED_CAST")
fun bindViewHolder(viewHolder: RecyclerView.ViewHolder, item: Any, position: Int) {
Holder<Type, Binding>(viewHolder)
.apply {
holderBinder(item as Type)
itemPosition = position
bindingBlock.invoke(binder.invoke(viewHolder.itemView), item)
}
fun bindViewHolder(viewHolder: RekuklerViewHolder<*, *>, item: Any, position: Int) {
viewHolder.bind(item, position)
}
}

@Suppress("UNCHECKED_CAST")
open class RekuklerViewHolder<Type: Any, Binding: ViewBinding>(
itemView: View,
val binder: (View) -> Binding,
private val holderBinder: HolderBinder<Type, Binding>.(Type) -> Unit
) : RecyclerView.ViewHolder(itemView) {

internal val holder = HolderBinder<Type, Binding>(this)
private var binding: Binding? = null

fun bind(item: Any, position: Int) {
holder.apply {
binding = binder.invoke(viewHolder.itemView)
holderBinder(item as Type)
itemPosition = position
bindingBlock.invoke(binding!!, item)
}
}

fun onDetachedFromWindow() {
binding?.let {
holder.onDetachedFromWindow.invoke(it)
}
}

fun onAttachedToWindow() {
binding?.let {
holder.onAttachedToWindow.invoke(it)
}
}

}

inline fun <reified Type: Any, Binder: ViewBinding> viewBinder(
@LayoutRes layoutResId: Int,
noinline isForItem: (item: Any) -> Boolean = { it is Type },
noinline areItemsSame: (Type, Type) -> Boolean = { old, new -> old == new },
noinline areContentsSame: (Type, Type) -> Boolean = { old, new -> old == new },
noinline binder: (View) -> Binder,
noinline holder: Holder<Type, Binder>.(Type) -> Unit = {}
noinline holderBinder: HolderBinder<Type, Binder>.(Type) -> Unit = {}
) = ViewBinder(
layoutResId = layoutResId,
binder = binder,
isForItem = isForItem,
areItemsSame = areItemsSame,
areContentsSame = areContentsSame,
holderBinder = holder
holderBinder = holderBinder
)

class Holder<Type: Any, Binding: ViewBinding>(
class HolderBinder<Type: Any, Binding: ViewBinding>(
val viewHolder: RecyclerView.ViewHolder
) {

internal var bindingBlock: Binding.(Type) -> Unit = {}
internal var onDetachedFromWindow: Binding.() -> Unit = {}
internal var onAttachedToWindow: Binding.() -> Unit = {}

internal var itemPosition = 0

val itemView: View
Expand All @@ -68,6 +103,14 @@ class Holder<Type: Any, Binding: ViewBinding>(
this.bindingBlock = bindingBlock
}

fun onDetachedFromWindow(b: Binding.() -> Unit) {
this.onDetachedFromWindow = b
}

fun onAttachedToWindow(b: Binding.() -> Unit) {
this.onAttachedToWindow = b
}

fun getString(@StringRes resId: Int): String = itemView.context.getString(resId)
fun getString(@StringRes resId: Int, vararg formatArgs: Any): String = itemView.context.getString(resId, *formatArgs)
fun getDrawable(@DrawableRes resId: Int): Drawable? = ContextCompat.getDrawable(itemView.context, resId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,13 @@ fun articlesBinder(
tvPosition.text = getString(R.string.position, position)
setOnClickListener { onClick.invoke(data) }
}

onDetachedFromWindow {
println("on item detached from window")
}

onAttachedToWindow {
println("on item attached to window")
}

}

0 comments on commit 7cfdea7

Please sign in to comment.