From 2cd7bae5e3237f7069b2b9cd0f054098ac19edda Mon Sep 17 00:00:00 2001 From: Jieyi Date: Fri, 31 Aug 2018 12:31:08 +0900 Subject: [PATCH] Feature: added the diff tool into adapter. Also, you can custom the diff util into. --- adaptiverecyclerview/build.gradle | 4 +- .../adaptiverecyclerview/AdaptiveAdapter.kt | 56 ++++++++++++++----- .../adaptiverecyclerview/AdaptiveDiffUtil.kt | 8 +++ .../java/com/devrapid/example/MainActivity.kt | 46 +++++++++------ sample/src/main/res/layout/activity_main.xml | 16 ++++++ 5 files changed, 99 insertions(+), 31 deletions(-) create mode 100644 adaptiverecyclerview/src/main/java/com/devrapid/adaptiverecyclerview/AdaptiveDiffUtil.kt diff --git a/adaptiverecyclerview/build.gradle b/adaptiverecyclerview/build.gradle index f9c4a48..bfddb4d 100644 --- a/adaptiverecyclerview/build.gradle +++ b/adaptiverecyclerview/build.gradle @@ -22,8 +22,8 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.0.0-alpha3' - implementation 'androidx.recyclerview:recyclerview:1.0.0-alpha3' + implementation 'androidx.appcompat:appcompat:1.0.0-rc02' + implementation 'androidx.recyclerview:recyclerview:1.0.0-rc02' } repositories { mavenCentral() diff --git a/adaptiverecyclerview/src/main/java/com/devrapid/adaptiverecyclerview/AdaptiveAdapter.kt b/adaptiverecyclerview/src/main/java/com/devrapid/adaptiverecyclerview/AdaptiveAdapter.kt index 2aff04c..1c072fc 100644 --- a/adaptiverecyclerview/src/main/java/com/devrapid/adaptiverecyclerview/AdaptiveAdapter.kt +++ b/adaptiverecyclerview/src/main/java/com/devrapid/adaptiverecyclerview/AdaptiveAdapter.kt @@ -3,6 +3,7 @@ package com.devrapid.adaptiverecyclerview import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView /** @@ -35,41 +36,70 @@ abstract class AdaptiveAdapter, VH : Re notifyItemChanged(dataList.size) } } + open var diffUtil: AdaptiveDiffUtil = MultiDiffUtil() + protected abstract var typeFactory: VT protected abstract var dataList: MutableList + inner class MultiDiffUtil : AdaptiveDiffUtil() { + override var oldList = mutableListOf() + override var newList = mutableListOf() + + override fun getOldListSize() = oldList.size + + override fun getNewListSize() = newList.size + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = + oldList[oldItemPosition].hashCode() == newList[newItemPosition].hashCode() + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = true + } + //region Necessary override methods. - override fun getItemCount(): Int = this.dataList.size + override fun getItemCount(): Int = dataList.size - override fun getItemViewType(position: Int): Int = this.dataList[position].type(this.typeFactory) + override fun getItemViewType(position: Int): Int = dataList[position].type(typeFactory) override fun onBindViewHolder(holder: VH, position: Int) = - (holder as AdaptiveViewHolder).initView(this.dataList[position], position, this) + (holder as AdaptiveViewHolder).initView(dataList[position], position, this) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH { val itemView: View = - LayoutInflater.from(parent.context).inflate(this.typeFactory.getLayoutResource(viewType), parent, false) + LayoutInflater.from(parent.context).inflate(typeFactory.getLayoutResource(viewType), parent, false) - return this.typeFactory.createViewHolder(viewType, itemView) as VH + return typeFactory.createViewHolder(viewType, itemView) as VH } //endregion - fun appendList(list: MutableList) { + open fun appendList(list: MutableList) { val startIndex = dataList.size - - dataList.addAll(startIndex, list) - notifyItemRangeChanged(startIndex, list.size) + val newList = dataList.toMutableList().apply { addAll(startIndex, list) } +// notifyItemRangeChanged(startIndex, list.size) + updateList { newList } } - fun dropList(startIndex: Int, endIndex: Int) { + open fun dropList(startIndex: Int, endIndex: Int) { when { startIndex < 0 || endIndex >= dataList.size -> throw IndexOutOfBoundsException("The range is over than list.") startIndex > endIndex -> throw IndexOutOfBoundsException("startIndex index must be less than endIndex index.") } + val newList = dataList.toMutableList() - repeat(endIndex - startIndex + 1) { dataList.removeAt(startIndex) } - notifyDataSetChanged() + repeat(endIndex - startIndex + 1) { newList.removeAt(startIndex) } +// notifyDataSetChanged() + updateList { newList } } - fun clearList() = dropList(0, dataList.size - 1) + open fun clearList() = dropList(0, dataList.size - 1) + + private fun updateList(getNewListBlock: () -> MutableList) { + val newList = getNewListBlock() + val res = DiffUtil.calculateDiff(diffUtil.apply { + oldList = dataList + this.newList = newList + }, true) + + dataList = newList + res.dispatchUpdatesTo(this) + } } diff --git a/adaptiverecyclerview/src/main/java/com/devrapid/adaptiverecyclerview/AdaptiveDiffUtil.kt b/adaptiverecyclerview/src/main/java/com/devrapid/adaptiverecyclerview/AdaptiveDiffUtil.kt new file mode 100644 index 0000000..1e7c87e --- /dev/null +++ b/adaptiverecyclerview/src/main/java/com/devrapid/adaptiverecyclerview/AdaptiveDiffUtil.kt @@ -0,0 +1,8 @@ +package com.devrapid.adaptiverecyclerview + +import androidx.recyclerview.widget.DiffUtil + +abstract class AdaptiveDiffUtil> : DiffUtil.Callback() { + abstract var oldList: MutableList + abstract var newList: MutableList +} diff --git a/sample/src/main/java/com/devrapid/example/MainActivity.kt b/sample/src/main/java/com/devrapid/example/MainActivity.kt index 1a15836..27bf096 100644 --- a/sample/src/main/java/com/devrapid/example/MainActivity.kt +++ b/sample/src/main/java/com/devrapid/example/MainActivity.kt @@ -5,28 +5,42 @@ import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager import com.devrapid.example.model.Animal import com.devrapid.example.model.Person +import kotlinx.android.synthetic.main.activity_main.btn_add +import kotlinx.android.synthetic.main.activity_main.btn_minus +import kotlinx.android.synthetic.main.activity_main.recyclerView -class MainActivity: AppCompatActivity() { +class MainActivity : AppCompatActivity() { + var a = 1 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val itemList: MutableList = mutableListOf(Person("Google"), - Person("Facebook", listOf(Animal("CEO"), - Animal("CTO"), - Animal("CDO"), - Animal("CAO"), - Animal("COO")), true), - Person("Apple", listOf(Animal("AEO"), - Animal("ATO"), - Animal("ADO")), true), - Person("Airbnb"), - Person("Jieyi")) + Person("Facebook", listOf(Animal("CEO"), + Animal("CTO"), + Animal("CDO"), + Animal("CAO"), + Animal("COO")), true), + Person("Apple", listOf(Animal("AEO"), + Animal("ATO"), + Animal("ADO")), true), + Person("Airbnb"), + Person("Jieyi")) - recyclerView.layoutManager = - androidx.recyclerview.widget.LinearLayoutManager(this, - androidx.recyclerview.widget.LinearLayoutManager.VERTICAL, - false) - recyclerView.adapter = ExpandAdapter(itemList) + val adapter = ExpandAdapter(itemList) + recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) + recyclerView.adapter = adapter + + btn_add.setOnClickListener { + adapter.appendList(listOf(Person("Google $a")) as MutableList) + a++ + } + btn_minus.setOnClickListener { + adapter.dropList(1, 1) + } + btn_minus.setOnLongClickListener { + adapter.clearList() + true + } } } diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 03bcee8..51d568a 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -21,4 +21,20 @@ app:layout_constraintTop_toTopOf="parent" tools:layout_editor_absoluteX="8dp" tools:layout_editor_absoluteY="8dp"/> + +