diff --git a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt index 6a72c911f..48e72de45 100644 --- a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt +++ b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt @@ -10,73 +10,72 @@ import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import java.util.* - /** * Created by Invincible on 2017/11/24. * * 通用的adapter 可添加header,footer,以及不同类型item */ -abstract class CommonRecyclerAdapter(protected val context: Context) : +abstract class CommonRecyclerAdapter(protected val context: Context): RecyclerView.Adapter() { - - constructor(context: Context, vararg delegates: ItemViewDelegate) : this(context) { + + constructor(context: Context, vararg delegates: ItemViewDelegate): this(context) { addItemViewDelegates(*delegates) } - + constructor( context: Context, vararg delegates: Pair> - ) : this(context) { + ): this(context) { addItemViewDelegates(*delegates) } - + private val inflater: LayoutInflater = LayoutInflater.from(context) - + private var headerItems: SparseArray? = null private var footerItems: SparseArray? = null - + private val itemDelegates: HashMap> = hashMapOf() private val items: MutableList = mutableListOf() - + private val lock = Object() - + private var itemClickListener: ((holder: ItemViewHolder, item: ITEM) -> Unit)? = null private var itemLongClickListener: ((holder: ItemViewHolder, item: ITEM) -> Boolean)? = null - - private var itemAnimation: ItemAnimation? = null - + + // 这个用Kotlin的setter就行了, 不需要手动开一个函数进行设置 + var itemAnimation: ItemAnimation? = null + fun setOnItemClickListener(listener: (holder: ItemViewHolder, item: ITEM) -> Unit) { itemClickListener = listener } - + fun setOnItemLongClickListener(listener: (holder: ItemViewHolder, item: ITEM) -> Boolean) { itemLongClickListener = listener } - + fun bindToRecyclerView(recyclerView: RecyclerView) { recyclerView.adapter = this } - - fun > addItemViewDelegate(viewType: Int, delegate: DELEGATE) { + + fun > addItemViewDelegate(viewType: Int, delegate: DELEGATE) { itemDelegates[viewType] = delegate } - - fun > addItemViewDelegate(delegate: DELEGATE) { + + fun > addItemViewDelegate(delegate: DELEGATE) { itemDelegates[itemDelegates.size] = delegate } - - fun > addItemViewDelegates(vararg delegates: DELEGATE) { + + fun > addItemViewDelegates(vararg delegates: DELEGATE) { delegates.forEach { addItemViewDelegate(it) } } - - fun addItemViewDelegates(vararg delegates: Pair>) { + + fun addItemViewDelegates(vararg delegates: Pair>) = delegates.forEach { addItemViewDelegate(it.first, it.second) } - } - + fun addHeaderView(header: View) { synchronized(lock) { if (headerItems == null) { @@ -89,8 +88,8 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - - fun addFooterView(footer: View) { + + fun addFooterView(footer: View) = synchronized(lock) { if (footerItems == null) { footerItems = SparseArray() @@ -101,9 +100,9 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : notifyItemInserted(index) } } - } - - fun removeHeaderView(header: View) { + + + fun removeHeaderView(header: View) = synchronized(lock) { headerItems?.let { val index = it.indexOfValue(header) @@ -113,9 +112,8 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - } - - fun removeFooterView(footer: View) { + + fun removeFooterView(footer: View) = synchronized(lock) { footerItems?.let { val index = it.indexOfValue(footer) @@ -125,8 +123,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - } - + fun setItems(items: List?) { synchronized(lock) { if (this.items.isNotEmpty()) { @@ -138,7 +135,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : notifyDataSetChanged() } } - + fun setItems(items: List?, diffResult: DiffUtil.DiffResult) { synchronized(lock) { if (this.items.isNotEmpty()) { @@ -150,7 +147,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : diffResult.dispatchUpdatesTo(this) } } - + fun setItem(position: Int, item: ITEM) { synchronized(lock) { val oldSize = getActualItemCount() @@ -160,7 +157,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - + fun addItem(item: ITEM) { synchronized(lock) { val oldSize = getActualItemCount() @@ -169,7 +166,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - + fun addItems(position: Int, newItems: List) { synchronized(lock) { if (this.items.addAll(position, newItems)) { @@ -177,7 +174,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - + fun addItems(newItems: List) { synchronized(lock) { val oldSize = getActualItemCount() @@ -190,7 +187,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - + fun removeItem(position: Int) { synchronized(lock) { if (this.items.removeAt(position) != null) { @@ -198,7 +195,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - + fun removeItem(item: ITEM) { synchronized(lock) { if (this.items.remove(item)) { @@ -206,7 +203,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - + fun removeItems(items: List) { synchronized(lock) { if (this.items.removeAll(items)) { @@ -214,7 +211,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - + fun swapItem(oldPosition: Int, newPosition: Int) { synchronized(lock) { val size = getActualItemCount() @@ -227,8 +224,8 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - - fun updateItem(item: ITEM) { + + fun updateItem(item: ITEM) = synchronized(lock) { val index = this.items.indexOf(item) if (index >= 0) { @@ -236,18 +233,16 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : notifyItemChanged(index) } } - } - - fun updateItem(position: Int, payload: Any) { + + fun updateItem(position: Int, payload: Any) = synchronized(lock) { val size = getActualItemCount() if (position in 0 until size) { notifyItemChanged(position + getHeaderCount(), payload) } } - } - - fun updateItems(fromPosition: Int, toPosition: Int, payloads: Any) { + + fun updateItems(fromPosition: Int, toPosition: Int, payloads: Any) = synchronized(lock) { val size = getActualItemCount() if (fromPosition in 0 until size && toPosition in 0 until size) { @@ -258,119 +253,94 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : ) } } - } - - fun clearItems() { + + fun clearItems() = synchronized(lock) { this.items.clear() notifyDataSetChanged() } - } - - fun isEmpty(): Boolean { - return items.isEmpty() - } - - fun isNotEmpty(): Boolean { - return items.isNotEmpty() - } - + + fun isEmpty() = items.isEmpty() + + fun isNotEmpty() = items.isNotEmpty() + /** * 除去header和footer */ - fun getActualItemCount(): Int { - return items.size - } - - fun getHeaderCount(): Int { - return headerItems?.size() ?: 0 - } - - fun getFooterCount(): Int { - return footerItems?.size() ?: 0 - } - + fun getActualItemCount() = items.size + + + fun getHeaderCount() = headerItems?.size() ?: 0 + + + fun getFooterCount() = footerItems?.size() ?: 0 + fun getItem(position: Int): ITEM? = items.getOrNull(position) - - fun getItemByLayoutPosition(position: Int): ITEM? { - val pos = position - getHeaderCount() - return items.getOrNull(pos) - } - + + fun getItemByLayoutPosition(position: Int) = items.getOrNull(position - getHeaderCount()) + fun getItems(): List = items - - protected open fun getItemViewType(item: ITEM, position: Int): Int { - return 0 - } - + + protected open fun getItemViewType(item: ITEM, position: Int) = 0 + /** * grid 模式下使用 */ - protected open fun getSpanSize(item: ITEM, viewType: Int, position: Int): Int { - return 1 - } - - final override fun getItemCount(): Int { - return getActualItemCount() + getHeaderCount() + getFooterCount() - } - - final override fun getItemViewType(position: Int): Int { - return when { - isHeader(position) -> TYPE_HEADER_VIEW + position - isFooter(position) -> TYPE_FOOTER_VIEW + position - getActualItemCount() - getHeaderCount() - else -> getItem(getActualPosition(position))?.let { - getItemViewType(it, getActualPosition(position)) - } ?: 0 + protected open fun getSpanSize(item: ITEM, viewType: Int, position: Int) = 1 + + final override fun getItemCount() = getActualItemCount() + getHeaderCount() + getFooterCount() + + final override fun getItemViewType(position: Int) = when { + isHeader(position) -> TYPE_HEADER_VIEW + position + isFooter(position) -> TYPE_FOOTER_VIEW + position - getActualItemCount() - getHeaderCount() + else -> getItem(getActualPosition(position))?.let { + getItemViewType(it, getActualPosition(position)) + } ?: 0 + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when { + viewType < TYPE_HEADER_VIEW + getHeaderCount() -> { + ItemViewHolder(headerItems!!.get(viewType)) } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - return when { - viewType < TYPE_HEADER_VIEW + getHeaderCount() -> { - ItemViewHolder(headerItems!!.get(viewType)) - } - - viewType >= TYPE_FOOTER_VIEW -> { - ItemViewHolder(footerItems!!.get(viewType)) - } - - else -> { - val holder = ItemViewHolder( - inflater.inflate( - itemDelegates.getValue(viewType).layoutId, - parent, - false - ) + + viewType >= TYPE_FOOTER_VIEW -> { + ItemViewHolder(footerItems!!.get(viewType)) + } + + else -> { + val holder = ItemViewHolder( + inflater.inflate( + itemDelegates.getValue(viewType).layoutId, + parent, + false ) - - itemDelegates.getValue(viewType) - .registerListener(holder) - - if (itemClickListener != null) { - holder.itemView.setOnClickListener { - getItem(holder.layoutPosition)?.let { - itemClickListener?.invoke(holder, it) - } + ) + + itemDelegates.getValue(viewType) + .registerListener(holder) + + if (itemClickListener != null) { + holder.itemView.setOnClickListener { + getItem(holder.layoutPosition)?.let { + itemClickListener?.invoke(holder, it) } } - - if (itemLongClickListener != null) { - holder.itemView.setOnLongClickListener { - getItem(holder.layoutPosition)?.let { - itemLongClickListener?.invoke(holder, it) ?: true - } ?: true - } + } + + if (itemLongClickListener != null) { + holder.itemView.setOnLongClickListener { + getItem(holder.layoutPosition)?.let { + itemLongClickListener?.invoke(holder, it) ?: true + } ?: true } - - holder } + + holder } } - - - final override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - } - + + final override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {} + final override fun onBindViewHolder( holder: ItemViewHolder, position: Int, @@ -383,19 +353,19 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - + override fun onViewAttachedToWindow(holder: ItemViewHolder) { super.onViewAttachedToWindow(holder) if (!isHeader(holder.layoutPosition) && !isFooter(holder.layoutPosition)) { addAnimation(holder) } } - + override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { super.onAttachedToRecyclerView(recyclerView) val manager = recyclerView.layoutManager if (manager is GridLayoutManager) { - manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { + manager.spanSizeLookup = object: GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { return getItem(position)?.let { if (isHeader(position) || isFooter(position)) manager.spanCount else getSpanSize( @@ -406,23 +376,13 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - - fun setItemAnimation(item: ItemAnimation) { - itemAnimation = item - } - - private fun isHeader(position: Int): Boolean { - return position < getHeaderCount() - } - - private fun isFooter(position: Int): Boolean { - return position >= getActualItemCount() + getHeaderCount() - } - - private fun getActualPosition(position: Int): Int { - return position - getHeaderCount() - } - + + private fun isHeader(position: Int) = position < getHeaderCount() + + private fun isFooter(position: Int) = position >= getActualItemCount() + getHeaderCount() + + private fun getActualPosition(position: Int) = position - getHeaderCount() + private fun addAnimation(holder: ItemViewHolder) { itemAnimation?.let { if (it.itemAnimEnabled) { @@ -433,8 +393,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - - + protected open fun startAnimation(holder: ItemViewHolder, item: ItemAnimation) { item.itemAnimation?.let { for (anim in it.getAnimators(holder.itemView)) { @@ -443,12 +402,12 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : } } } - + companion object { private const val TYPE_HEADER_VIEW = Int.MIN_VALUE private const val TYPE_FOOTER_VIEW = Int.MAX_VALUE - 999 } - + }