From 0a3c5e02734040b8f36342cb78bdb6f022365dac Mon Sep 17 00:00:00 2001 From: Dima Ivanov Date: Thu, 4 Feb 2021 16:35:58 +0300 Subject: [PATCH 1/2] Added onItemMove to MultibindingAdapter --- .../rerekt/rekukler/ItemTouchHelperAdapter.kt | 5 +++ .../rerekt/rekukler/MultibindingsAdapter.kt | 40 +++++++++++++++---- .../java/com/rerekt/rekukler/RecyclerUtils.kt | 15 +------ .../com/rerekt/rekukler/RecyclerViewDSL.kt | 11 ++--- .../java/com/rerekt/sample/ui/ListFragment.kt | 16 +++----- .../com/rerekt/sample/ui/global/ViewExt.kt | 5 ++- .../rerekt/sample/ui/global/list/articles.kt | 10 +++++ sample/src/main/res/layout/list_item.xml | 1 + 8 files changed, 65 insertions(+), 38 deletions(-) create mode 100644 rekukler/src/main/java/com/rerekt/rekukler/ItemTouchHelperAdapter.kt diff --git a/rekukler/src/main/java/com/rerekt/rekukler/ItemTouchHelperAdapter.kt b/rekukler/src/main/java/com/rerekt/rekukler/ItemTouchHelperAdapter.kt new file mode 100644 index 0000000..a65a86a --- /dev/null +++ b/rekukler/src/main/java/com/rerekt/rekukler/ItemTouchHelperAdapter.kt @@ -0,0 +1,5 @@ +package com.rerekt.rekukler + +interface ItemTouchHelperAdapter { + fun onItemMove(fromPosition: Int, toPosition: Int): Boolean +} \ No newline at end of file diff --git a/rekukler/src/main/java/com/rerekt/rekukler/MultibindingsAdapter.kt b/rekukler/src/main/java/com/rerekt/rekukler/MultibindingsAdapter.kt index 06ab23f..f386ade 100644 --- a/rekukler/src/main/java/com/rerekt/rekukler/MultibindingsAdapter.kt +++ b/rekukler/src/main/java/com/rerekt/rekukler/MultibindingsAdapter.kt @@ -4,10 +4,11 @@ import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding +import java.util.Collections open class MultiBindingAdapter( vararg binders: ViewBinder<*, *> -): RecyclerView.Adapter() { +): RecyclerView.Adapter(), ItemTouchHelperAdapter { var items: List = listOf() set(value) { @@ -32,13 +33,24 @@ open class MultiBindingAdapter( override fun getItemCount() = items.size private fun updateList(newList: List) { - DiffUtil.calculateDiff(object: DiffUtil.Callback() { + DiffUtil.calculateDiff(object : DiffUtil.Callback() { override fun getOldListSize() = items.size override fun getNewListSize() = newList.size override fun areItemsTheSame(old: Int, new: Int) = - kotlin.runCatching { bindersSet.find { it.isForItem(items[old]) }?.areItemsSame?.invoke(items[old], newList[new]) ?: false }.getOrElse { false } + kotlin.runCatching { + bindersSet.find { it.isForItem(items[old]) }?.areItemsSame?.invoke( + items[old], + newList[new] + ) ?: false + }.getOrElse { false } + override fun areContentsTheSame(old: Int, new: Int) = - kotlin.runCatching { bindersSet.find { it.isForItem(items[old]) }?.areContentsSame?.invoke(items[old], newList[new]) ?: false }.getOrElse { false } + kotlin.runCatching { + bindersSet.find { it.isForItem(items[old]) }?.areContentsSame?.invoke( + items[old], + newList[new] + ) ?: false + }.getOrElse { false } }).dispatchUpdatesTo(this) } @@ -49,8 +61,22 @@ open class MultiBindingAdapter( private fun getBinder(position: Int): ViewBinder<*, *> { val item = items[position] return checkNotNull( - value = bindersSet.find { it.isForItem(item) }, - lazyMessage = { "Unnable to find ViewBinder for ${item::class}" } - ) + value = bindersSet.find { it.isForItem(item) }, + lazyMessage = { "Unnable to find ViewBinder for ${item::class}" } + ) } + + override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean { + if (fromPosition < toPosition) { + for (i in fromPosition until toPosition) { + Collections.swap(items.toList(), i, i + 1) + } + } else { + for (i in fromPosition downTo toPosition + 1) { + Collections.swap(items.toList(), i, i - 1) + } + } + notifyItemMoved(fromPosition, toPosition) + return true + } } \ No newline at end of file diff --git a/rekukler/src/main/java/com/rerekt/rekukler/RecyclerUtils.kt b/rekukler/src/main/java/com/rerekt/rekukler/RecyclerUtils.kt index 717ab5d..2f67e3a 100644 --- a/rekukler/src/main/java/com/rerekt/rekukler/RecyclerUtils.kt +++ b/rekukler/src/main/java/com/rerekt/rekukler/RecyclerUtils.kt @@ -15,17 +15,4 @@ internal fun clip(size: Int, start: Int, end: Int, delta: Float): Float { outOfBorderEnd > 0 -> delta - outOfBorderEnd else -> delta } -} - -fun List.swapListItems(fromPosition: Int, toPosition: Int): List = - apply { - if (fromPosition < toPosition) { - for (i in fromPosition until toPosition) { - Collections.swap(this, i, i + 1) - } - } else { - for (i in fromPosition downTo toPosition + 1) { - Collections.swap(this, i, i - 1) - } - } - } \ No newline at end of file +} \ No newline at end of file diff --git a/rekukler/src/main/java/com/rerekt/rekukler/RecyclerViewDSL.kt b/rekukler/src/main/java/com/rerekt/rekukler/RecyclerViewDSL.kt index 3e5d60a..f03ed73 100644 --- a/rekukler/src/main/java/com/rerekt/rekukler/RecyclerViewDSL.kt +++ b/rekukler/src/main/java/com/rerekt/rekukler/RecyclerViewDSL.kt @@ -71,7 +71,7 @@ class RecyclerViewConfig( onSwiped: (RecyclerView.ViewHolder, direction: Int) -> Unit = { _, _ -> }, onClearView: () -> Unit = {}, isCanBeOutOfBounds: Boolean = false, - onMove: (RecyclerView.ViewHolder, RecyclerView.ViewHolder) -> Boolean = { _, _ -> true } + onMove: ((RecyclerView.ViewHolder, RecyclerView.ViewHolder) -> Boolean)? = null ) = ItemTouchHelper( object : ItemTouchHelper.Callback() { override fun getMovementFlags( @@ -87,6 +87,7 @@ class RecyclerViewConfig( viewHolder: RecyclerView.ViewHolder ) = onClearView.invoke() override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) { + viewHolder.itemView.outlineProvider = null if (isCanBeOutOfBounds) { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) } else { @@ -96,10 +97,10 @@ class RecyclerViewConfig( } } override fun onMove( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean = onMove.invoke(viewHolder, target) + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean = onMove?.invoke(viewHolder, target) ?: (recyclerView.adapter as? MultiBindingAdapter)?.onItemMove(viewHolder.adapterPosition, target.adapterPosition) ?: false } ).apply { itemTouchHelper = this } diff --git a/sample/src/main/java/com/rerekt/sample/ui/ListFragment.kt b/sample/src/main/java/com/rerekt/sample/ui/ListFragment.kt index 669a65d..09c376d 100644 --- a/sample/src/main/java/com/rerekt/sample/ui/ListFragment.kt +++ b/sample/src/main/java/com/rerekt/sample/ui/ListFragment.kt @@ -2,12 +2,13 @@ package com.rerekt.sample.ui import android.os.Bundle import android.view.View +import android.widget.LinearLayout import androidx.fragment.app.Fragment -import androidx.recyclerview.widget.LinearLayoutManager import com.rerekt.rekukler.* import com.rerekt.sample.R import com.rerekt.sample.databinding.FragmentMainBinding import com.rerekt.sample.ui.global.dip +import com.rerekt.sample.ui.global.int import com.rerekt.sample.ui.global.list.* class ListFragment: Fragment(R.layout.fragment_main) { @@ -33,7 +34,7 @@ class ListFragment: Fragment(R.layout.fragment_main) { private fun postDelayedListUpdate() { articlesAdapter.items = buildList { addAll( - (0..10).map { + (0..20).map { Article( id = it, title = "Title#$it", @@ -49,19 +50,12 @@ class ListFragment: Fragment(R.layout.fragment_main) { binding.rvArticles.apply { configure(articlesAdapter) { linearLayout { - reverseLayout = false - orientation = LinearLayoutManager.VERTICAL + orientation = LinearLayout.VERTICAL } dividerItemDecoration( size = 2.dip(resources).toInt() ) - itemTouchHelper { draggedHolder, target -> - getItems
() - ?.toList() - ?.swapListItems(draggedHolder.layoutPosition, target.layoutPosition) - ?.let { updateList(it) } - true - } + itemTouchHelper() } } } diff --git a/sample/src/main/java/com/rerekt/sample/ui/global/ViewExt.kt b/sample/src/main/java/com/rerekt/sample/ui/global/ViewExt.kt index 1a9f3e4..0b71bdf 100644 --- a/sample/src/main/java/com/rerekt/sample/ui/global/ViewExt.kt +++ b/sample/src/main/java/com/rerekt/sample/ui/global/ViewExt.kt @@ -8,4 +8,7 @@ fun Int.dip(resource: Resources) = TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), resource.displayMetrics - ) \ No newline at end of file + ) + +val Float.int: Int + get() = toInt() \ No newline at end of file diff --git a/sample/src/main/java/com/rerekt/sample/ui/global/list/articles.kt b/sample/src/main/java/com/rerekt/sample/ui/global/list/articles.kt index 9592c76..818c2d0 100644 --- a/sample/src/main/java/com/rerekt/sample/ui/global/list/articles.kt +++ b/sample/src/main/java/com/rerekt/sample/ui/global/list/articles.kt @@ -1,5 +1,6 @@ package com.rerekt.sample.ui.global.list +import androidx.core.content.ContextCompat import com.rerekt.rekukler.viewBinder import com.rerekt.sample.R import com.rerekt.sample.databinding.ListItemBinding @@ -20,6 +21,15 @@ fun articlesBinder( areContentsSame = { old, new -> old == new }, ) { bindView { data -> + llContainer.setBackgroundColor( + ContextCompat.getColor( + itemView.context, + if (position % 2 == 0) + android.R.color.holo_red_dark + else + android.R.color.holo_green_dark + ) + ) tvTitle.text = data.title tvDescription.text = data.description tvPosition.text = getString(R.string.position, position) diff --git a/sample/src/main/res/layout/list_item.xml b/sample/src/main/res/layout/list_item.xml index 20c54f2..cf0f46a 100644 --- a/sample/src/main/res/layout/list_item.xml +++ b/sample/src/main/res/layout/list_item.xml @@ -1,5 +1,6 @@ Date: Fri, 5 Feb 2021 10:52:46 +0300 Subject: [PATCH 2/2] Removed ItemTouchHelperAdapter, added moveItems function --- .../main/java/com/rerekt/rekukler/ItemTouchHelperAdapter.kt | 5 ----- .../main/java/com/rerekt/rekukler/MultibindingsAdapter.kt | 4 ++-- rekukler/src/main/java/com/rerekt/rekukler/RecyclerUtils.kt | 2 -- .../src/main/java/com/rerekt/rekukler/RecyclerViewDSL.kt | 2 +- 4 files changed, 3 insertions(+), 10 deletions(-) delete mode 100644 rekukler/src/main/java/com/rerekt/rekukler/ItemTouchHelperAdapter.kt diff --git a/rekukler/src/main/java/com/rerekt/rekukler/ItemTouchHelperAdapter.kt b/rekukler/src/main/java/com/rerekt/rekukler/ItemTouchHelperAdapter.kt deleted file mode 100644 index a65a86a..0000000 --- a/rekukler/src/main/java/com/rerekt/rekukler/ItemTouchHelperAdapter.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.rerekt.rekukler - -interface ItemTouchHelperAdapter { - fun onItemMove(fromPosition: Int, toPosition: Int): Boolean -} \ No newline at end of file diff --git a/rekukler/src/main/java/com/rerekt/rekukler/MultibindingsAdapter.kt b/rekukler/src/main/java/com/rerekt/rekukler/MultibindingsAdapter.kt index f386ade..1adad5e 100644 --- a/rekukler/src/main/java/com/rerekt/rekukler/MultibindingsAdapter.kt +++ b/rekukler/src/main/java/com/rerekt/rekukler/MultibindingsAdapter.kt @@ -8,7 +8,7 @@ import java.util.Collections open class MultiBindingAdapter( vararg binders: ViewBinder<*, *> -): RecyclerView.Adapter(), ItemTouchHelperAdapter { +): RecyclerView.Adapter() { var items: List = listOf() set(value) { @@ -66,7 +66,7 @@ open class MultiBindingAdapter( ) } - override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean { + fun moveItems(fromPosition: Int, toPosition: Int): Boolean { if (fromPosition < toPosition) { for (i in fromPosition until toPosition) { Collections.swap(items.toList(), i, i + 1) diff --git a/rekukler/src/main/java/com/rerekt/rekukler/RecyclerUtils.kt b/rekukler/src/main/java/com/rerekt/rekukler/RecyclerUtils.kt index 2f67e3a..7ac8458 100644 --- a/rekukler/src/main/java/com/rerekt/rekukler/RecyclerUtils.kt +++ b/rekukler/src/main/java/com/rerekt/rekukler/RecyclerUtils.kt @@ -1,7 +1,5 @@ package com.rerekt.rekukler -import java.util.* - //Function for clip the borders internal fun clip(size: Int, start: Int, end: Int, delta: Float): Float { val newStart = start + delta diff --git a/rekukler/src/main/java/com/rerekt/rekukler/RecyclerViewDSL.kt b/rekukler/src/main/java/com/rerekt/rekukler/RecyclerViewDSL.kt index f03ed73..8719ae5 100644 --- a/rekukler/src/main/java/com/rerekt/rekukler/RecyclerViewDSL.kt +++ b/rekukler/src/main/java/com/rerekt/rekukler/RecyclerViewDSL.kt @@ -100,7 +100,7 @@ class RecyclerViewConfig( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder - ): Boolean = onMove?.invoke(viewHolder, target) ?: (recyclerView.adapter as? MultiBindingAdapter)?.onItemMove(viewHolder.adapterPosition, target.adapterPosition) ?: false + ): Boolean = onMove?.invoke(viewHolder, target) ?: (recyclerView.adapter as? MultiBindingAdapter)?.moveItems(viewHolder.adapterPosition, target.adapterPosition) ?: false } ).apply { itemTouchHelper = this }