如何在回收器视图(Kotlin)的末端添加按钮?

发布于 2025-02-13 22:46:03 字数 1574 浏览 5 评论 0原文

我要在回收器视图的末端添加一个按钮 我不知道该怎么做。 如果你教我,我会感谢你的。

这是我的主要活动代码:

class MainActivity : AppCompatActivity() {
private var number: Int = 0
private lateinit var name: String

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val myRecyclerView = findViewById<RecyclerView>(R.id.recyclerView)
    val myViewModel = ViewModel()
    myRecyclerView.layoutManager = LinearLayoutManager(this)

    myViewModel.getUserData()




    myViewModel.myList.observe(this) {
     
        myRecyclerView.adapter = MyAdapter(it)
    }


}

这是我的适配器代码:

class MyAdapter(private val myList: List<Player>) : RecyclerView.Adapter<MyHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
    val myLayoutInflater = LayoutInflater.from(parent.context)
    val myView = myLayoutInflater.inflate(R.layout.view_for_rv, parent, false)
    return MyHolder(myView)

}

override fun onBindViewHolder(holder: MyHolder, position: Int) {
    val item = myList[position]
    holder.bind(item)


}

override fun getItemCount(): Int {
    return myList.size
}

和我的持有人类:

class MyHolder(view: View) : RecyclerView.ViewHolder(view) {
private val playerNumber  = view.findViewById<TextView>(R.id.tvNumber)
private val playerName = view.findViewById<TextView>(R.id.tvName)

fun bind(item : Player){
    playerName.text=item.name
    playerNumber.text=item.number.toString()
}

I'm gonna add a button at the end of my recycler view
and i don't know how to do it .
i will appreciate you if you teach me .

this is my main activity code :

class MainActivity : AppCompatActivity() {
private var number: Int = 0
private lateinit var name: String

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val myRecyclerView = findViewById<RecyclerView>(R.id.recyclerView)
    val myViewModel = ViewModel()
    myRecyclerView.layoutManager = LinearLayoutManager(this)

    myViewModel.getUserData()




    myViewModel.myList.observe(this) {
     
        myRecyclerView.adapter = MyAdapter(it)
    }


}

and this is my adapter code :

class MyAdapter(private val myList: List<Player>) : RecyclerView.Adapter<MyHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
    val myLayoutInflater = LayoutInflater.from(parent.context)
    val myView = myLayoutInflater.inflate(R.layout.view_for_rv, parent, false)
    return MyHolder(myView)

}

override fun onBindViewHolder(holder: MyHolder, position: Int) {
    val item = myList[position]
    holder.bind(item)


}

override fun getItemCount(): Int {
    return myList.size
}

and my holder class :

class MyHolder(view: View) : RecyclerView.ViewHolder(view) {
private val playerNumber  = view.findViewById<TextView>(R.id.tvNumber)
private val playerName = view.findViewById<TextView>(R.id.tvName)

fun bind(item : Player){
    playerName.text=item.name
    playerNumber.text=item.number.toString()
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

﹏雨一样淡蓝的深情 2025-02-20 22:46:05

您将通过在父nestedscrollview中添加recyclerview来实现这一目标,然后将button放在recyclerview下方。

因此您的代码应该看起来像此

<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</androidx.core.widget.NestedScrollView>

注释

添加recyclerview.nestedscrollingenabled = false scroll以适用于SDK 21

You will achieve this by adding the RecyclerView in a parent NestedScrollView and then place the Button below the RecyclerView.

So your code should look like this

<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</androidx.core.widget.NestedScrollView>

NOTE

Add recyclerView.nestedScrollingEnabled = false for scroll to work for sdk 21

云柯 2025-02-20 22:46:05

添加新项目类型是很好的选择。

class MyAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    companion object {
        const val ITEM_TYPE_CONTENT = 0
        const val ITEM_TYPE_BUTTON = 1
    }

    val dataList: List<String>? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        if (viewType == ITEM_TYPE_CONTENT) {
            // TODO return a content holder
        }else {
            // TODO return a button holder
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        TODO("Not yet implemented")
    }

    override fun getItemCount(): Int {
        return (dataList?.size ?: 0) + 1
    }

    override fun getItemViewType(position: Int): Int {
        return if (position == itemCount - 1) {
            ITEM_TYPE_BUTTON
        } else {
            ITEM_TYPE_CONTENT
        }
    }
}

add a new itemType is good selection。

class MyAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    companion object {
        const val ITEM_TYPE_CONTENT = 0
        const val ITEM_TYPE_BUTTON = 1
    }

    val dataList: List<String>? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        if (viewType == ITEM_TYPE_CONTENT) {
            // TODO return a content holder
        }else {
            // TODO return a button holder
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        TODO("Not yet implemented")
    }

    override fun getItemCount(): Int {
        return (dataList?.size ?: 0) + 1
    }

    override fun getItemViewType(position: Int): Int {
        return if (position == itemCount - 1) {
            ITEM_TYPE_BUTTON
        } else {
            ITEM_TYPE_CONTENT
        }
    }
}
计㈡愣 2025-02-20 22:46:05

您可以使用

package com.joon.fm.core.base.genericRecycler


import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import androidx.core.util.set
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.joon.fm.core.extensions.getClass
import com.joon.fm.features.explore.section.SectionExploreNewReleases
import java.lang.reflect.Constructor
import java.util.concurrent.atomic.AtomicInteger


interface GenericAdapterView<Model> {
    fun onBind(model: Model, position: Int, extraObject: Any?)
}

data class Section<Model>(
    var type: Int,
    var data: Model,
    var extraObject: Any?,
    var index: Int = -1
)

open class VH(view: View) : RecyclerView.ViewHolder(view)

interface DiffUtilModel {
    fun areItemsTheSame(o: DiffUtilModel): Boolean
    fun areContentsTheSame(o: DiffUtilModel): Boolean
}

class MyDiffCallback(private val oldList: List<Any?>, private val newList: List<Any?>) :
    DiffUtil.Callback() {
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val old = oldList[oldItemPosition]
        val new = newList[newItemPosition]
        if (old is DiffUtilModel && new is DiffUtilModel) {
            return old.areItemsTheSame(new)
        }
        return oldList[oldItemPosition] == newList[newItemPosition]
    }

    override fun getOldListSize() = oldList.size

    override fun getNewListSize() = newList.size

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val old = oldList[oldItemPosition]
        val new = newList[newItemPosition]
        if (old is DiffUtilModel && new is DiffUtilModel) {
            return old.areContentsTheSame(new)
        }
        return (old == null && new == null) || (old != null && old == new)
    }

}

@Suppress("unused")
open class AppGenericAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    val sections = ArrayList<Section<*>>()
    var providers = SparseArray<(ViewGroup, Int) -> View>()

    private var types = HashMap<Class<*>, Pair<Int, Constructor<*>?>>()
    private var typeIds = AtomicInteger(0)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return VH(providers[viewType](parent, viewType))
    }


    @Suppress("UNCHECKED_CAST")
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val v = holder.itemView as? GenericAdapterView<Any>
        val sec = sections[position]
        sec.data?.run {
            v?.onBind(this, position, sec.extraObject)
        }
    }

    override fun getItemCount() = sections.size
    override fun getItemViewType(position: Int) = sections[position].type


    inline fun <reified V : View> viewType(addDefaultProvider: Boolean = true) =
        viewType(V::class.java, addDefaultProvider)

    fun viewType(cls: Class<*>, addDefaultProvider: Boolean = true): Int {
        val prevAns = types[cls]
        if (prevAns == null) {
            var cons: Constructor<*>? = null
            try {
                cons = cls.getDeclaredConstructor(Context::class.java)
            } catch (ignored: Throwable) {
            }
            types[cls] = Pair(typeIds.getAndIncrement(), cons)

            val type = types[cls]!!

            if (addDefaultProvider && providers[type.first] == null) {
                providers[type.first] = { vg, _ ->
                    type.second!!.newInstance(vg.context) as View
                }

            }
            return type.first
        } else {
            return prevAns.first
        }
    }


    inline fun <reified V> setProvider(noinline provider: (ViewGroup, Int) -> V) where V : View, V : GenericAdapterView<*> {
        providers[viewType<V>(false)] = provider
    }

    inline fun <reified V> provider(noinline provider: (Context) -> V) where V : View, V : GenericAdapterView<*> {
        providers[viewType<V>(false)] = { vg, _ -> provider(vg.context) }
    }

    inline fun <reified V> addProvider(noinline provider: (Context) -> V) where V : View, V : GenericAdapterView<*> {
        providers.set(viewType<V>(false)) { vg, _ -> provider(vg.context) }
    }


    inline fun <reified V, reified Model : Any> setSections(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.clear()
        addSections<V, Model>(data, extra)
    }

    inline fun <reified V, reified Model : Any> setSectionsDiffUtil(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {

        val diffCallback = MyDiffCallback(sections.map { it.data }, data.toList())
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        sections.clear()
        addSections<V, Model>(data, extra)
        diffResult.dispatchUpdatesTo(this)

    }

    fun setSectionsDiffUtil(newSections: Collection<Section<*>>) {
        val diffCallback = MyDiffCallback(sections.map { it.data }, newSections.map { it.data })
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        sections.clear()
        sections.addAll(newSections)
        diffResult.dispatchUpdatesTo(this)
    }

    inline fun <reified V, reified Model : Any> setSectionsAndNotify(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        setSections<V, Model>(data, extra)
        notifyDataSetChanged()
    }
    fun  removeItemFromSectionsAndNotify(
        index: Int,
    ) {
        sections.removeAt(index)
        notifyDataSetChanged()
    }

    inline fun <reified V, reified Model : Any> setSectionsAndNotifyRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val prevSize = itemCount
        setSections<V, Model>(data, extra)
        val newSize = itemCount
        notifyItemRangeChanged(0, newSize)
        if (prevSize > newSize) {
            notifyItemRangeRemoved(newSize, prevSize - newSize)
        }
    }


    inline fun <reified V, reified Model : Any> addSections(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val type = viewType<V>()
        sections.addAll(data.map { Section(type, it, extra) })
    }

    inline fun <reified V> addView(
    ) where V : View {
        val type = viewType<V>()
        sections.add(Section(viewType<V>(), null, null))
    }

    inline fun <reified V, reified Model : Any> addSectionsAndNotify(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyDataSetChanged()
    }

    inline fun <reified V, reified Model : Any> addSectionsAndNotifyRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyItemRangeChanged(itemCount - data.size, itemCount)
    }
    inline fun <reified V, reified Model : Any> addSectionsAndNotifyCompleteRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyItemRangeChanged(itemCount - data.size, itemCount)
    }


    inline fun <reified V, reified Model : Any?> setSection(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections[position] = Section(viewType<V>(), data, extra)
    }

    inline fun <reified V, reified Model : Any?> setSectionAndNotify(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        setSection<V, Model>(position, data, extra)
        notifyItemChanged(position)
    }

    fun updateSection(
        position: Int,
    ) {
        notifyItemChanged(position)
        Handler(Looper.getMainLooper()).post {
            notifyItemChanged(position)
        }
    }
    
    inline fun <reified V, reified Model : Any> addSection(
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.add(Section(viewType<V>(), data, extra))
    }

    inline fun <reified V, reified Model : Any> addSectionAndNotify(
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSection<V, Model>(data, extra)
        notifyItemInserted(sections.size - 1)
    }

    inline fun <reified V, reified Model : Any?> createEmptySection(
        data: Model?,
        extra: Any? = null
    ): Section<Model?> where V : View, V : GenericAdapterView<Model> =
        Section(viewType<V>(), data, extra)

    inline fun <reified V, reified Model : Any> createSection(
        data: Model,
        extra: Any? = null
    ): Section<Model> where V : View, V : GenericAdapterView<Model> =
        Section(viewType<V>(), data, extra)


    inline fun <reified V, reified Model : Any> addSection(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.add(position, Section(viewType<V>(), data, extra))
    }

    inline fun <reified V, reified Model : Any?> addEmpotySection(
        position: Int,
        data: Model? = null,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val type = viewType<V>()
        if (sections.find { it.type == type } != null) {
            sections.add(position, Section(viewType<V>(), data, extra))
            val index = sections.indexOfLast { it.type == type }
            providers.delete(index)
            sections.removeAt(index)
            notifyItemRangeChanged(index-1,1)
        } else {
            sections.add(position, Section(viewType<V>(), data, extra))
            notifyItemInserted(position)
        }
    }

    inline fun <reified V, reified Model : Any> addSectionAndNotify(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSection<V, Model>(position, data, extra)
        notifyItemInserted(position)
    }


    inline fun <reified V, reified Model : Any> createSections(
        data: Collection<Model>,
        extra: Any? = null
    ): List<Section<Model>> where V : View, V : GenericAdapterView<Model> =
        data.map { Section(viewType<V>(), it, extra) }


    fun createSection(
        cls: Class<*>,
        data: Any,
        extra: Any? = null
    ): Section<*> =
        Section(viewType(cls), data, extra)


    fun clearData() {
        sections.clear()
    }

    fun clearDataAndNotify() {
        sections.clear()
        providers.clear()
        notifyDataSetChanged()
    }

    inline fun <reified V : View> clearViews() {
        val type = viewType<V>()
        sections.removeAll { it.type == type }
    }

    inline fun <reified V : View> findIndexItem(): Int {
        val type = viewType<V>()
        var item = 0
        sections.forEachIndexed { index, section ->
            if (section.type == type) {
                item = index
            }
        }
        return item
    }

    inline fun <reified V : View> findIndexItemNew(): Int? {
        val type = viewType<V>()
        var item: Int? = null
        sections.forEachIndexed { index, section ->
            if (section.type == type) {
                item = index
            }
        }
        return item
    }

    inline fun <reified V : View> clearSectionsWithTypeAndNotify() {
        clearViews<V>()
        notifyItemRemoved(viewType<V>(false))
        providers.delete(viewType<V>(false))
    }

    inline fun <reified T> sectionsWithType(): List<Section<T>> =
        sections.mapIndexed { index, section -> section.index = index; section }
            .filter { it.data is T }.map { it as Section<T> }

}

fun AppGenericAdapter.setSectionsInViewsListAndTryToRecycle(
    parent: ViewGroup,
    lpProvider: (AppGenericAdapter.(Section<*>, Int) -> ViewGroup.LayoutParams)? = null
) {
    for (i in 0 until sections.size) {
        val section = sections[i]
        if (i < parent.childCount) {
            try {
                val child = parent.getChildAt(i) as GenericAdapterView<Any>
                child.onBind(section.data as Any, i, section.extraObject)
            } catch (e: Exception) {
                parent.removeAllViews()
                setSectionsInViewsListAndTryToRecycle(parent)
            }
        } else {
            val vh = onCreateViewHolder(parent, section.type)
            if (vh.itemView is GenericAdapterView<*>) {
                (vh.itemView as GenericAdapterView<Any>).onBind(
                    section.data!!,
                    i,
                    section.extraObject
                )
            }
            if (lpProvider != null) {
                vh.itemView.layoutParams = lpProvider(section, i)
            }
            parent.addView(vh.itemView)
        }
    }
    if (parent.childCount - sections.size > 0) {
        parent.removeViews(sections.size, parent.childCount - sections.size)
    }
}

这是一个通用适配器类,可以在简单适配器的所有项目实例中使用。您只需添加一个项目并将其传递给通用类即可创建您的列表。

如何用户
首先,您必须将此课程添加到您的项目中。

abstract class BaseCustomView<viewDataBinding : ViewDataBinding> @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {
    lateinit var binding: viewDataBinding

    init {
        this.inflate(context, attrs)
    }

    @CallSuper
    protected open fun inflate(context: Context, attrs: AttributeSet?){

        val bindingClass = javaClass.findGenericWithType<viewDataBinding>(ViewDataBinding::class.java)

        if(isInEditMode){
            if(bindingClass != null){
                val resId = bindingClass.layoutId(context)
                LayoutInflater.from(context).inflate(resId, this, true)
            }
        } else {
            binding = bindingClass?.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java)?.invoke(null, LayoutInflater.from(context), this, true) as viewDataBinding
            binding.setView(this)
        }
    }


}

之后,您的项目(VH)必须像这样继承此类

class YourItem @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : BaseCustomView<YouBinding>(context, attrs, defStyleAttr),
    GenericAdapterView<Model> {
    override fun onBind(model: Model, position: Int, extraObject: Any?) {
    }
}

,最后将项目附加到适配器

private val adapter = AppGenericAdapter().apply {
    provider { context ->
        YourItem (context,)// if you want to pass extra data you can pass data as arg
    }
    provider { context ->
        YourItemButton(context,)// if you want to pass extra data you can pass data as arg
    }
}

binding.recycler.adapter = adapter
adapter.addSectionsAndNotify<YourItem , Model>(data)
// you can check with if the last item add this item
adapter.addSectionsAndNotify<YourItemButton , Model>(data)

You can use this

package com.joon.fm.core.base.genericRecycler


import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import androidx.core.util.set
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.joon.fm.core.extensions.getClass
import com.joon.fm.features.explore.section.SectionExploreNewReleases
import java.lang.reflect.Constructor
import java.util.concurrent.atomic.AtomicInteger


interface GenericAdapterView<Model> {
    fun onBind(model: Model, position: Int, extraObject: Any?)
}

data class Section<Model>(
    var type: Int,
    var data: Model,
    var extraObject: Any?,
    var index: Int = -1
)

open class VH(view: View) : RecyclerView.ViewHolder(view)

interface DiffUtilModel {
    fun areItemsTheSame(o: DiffUtilModel): Boolean
    fun areContentsTheSame(o: DiffUtilModel): Boolean
}

class MyDiffCallback(private val oldList: List<Any?>, private val newList: List<Any?>) :
    DiffUtil.Callback() {
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val old = oldList[oldItemPosition]
        val new = newList[newItemPosition]
        if (old is DiffUtilModel && new is DiffUtilModel) {
            return old.areItemsTheSame(new)
        }
        return oldList[oldItemPosition] == newList[newItemPosition]
    }

    override fun getOldListSize() = oldList.size

    override fun getNewListSize() = newList.size

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val old = oldList[oldItemPosition]
        val new = newList[newItemPosition]
        if (old is DiffUtilModel && new is DiffUtilModel) {
            return old.areContentsTheSame(new)
        }
        return (old == null && new == null) || (old != null && old == new)
    }

}

@Suppress("unused")
open class AppGenericAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    val sections = ArrayList<Section<*>>()
    var providers = SparseArray<(ViewGroup, Int) -> View>()

    private var types = HashMap<Class<*>, Pair<Int, Constructor<*>?>>()
    private var typeIds = AtomicInteger(0)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return VH(providers[viewType](parent, viewType))
    }


    @Suppress("UNCHECKED_CAST")
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val v = holder.itemView as? GenericAdapterView<Any>
        val sec = sections[position]
        sec.data?.run {
            v?.onBind(this, position, sec.extraObject)
        }
    }

    override fun getItemCount() = sections.size
    override fun getItemViewType(position: Int) = sections[position].type


    inline fun <reified V : View> viewType(addDefaultProvider: Boolean = true) =
        viewType(V::class.java, addDefaultProvider)

    fun viewType(cls: Class<*>, addDefaultProvider: Boolean = true): Int {
        val prevAns = types[cls]
        if (prevAns == null) {
            var cons: Constructor<*>? = null
            try {
                cons = cls.getDeclaredConstructor(Context::class.java)
            } catch (ignored: Throwable) {
            }
            types[cls] = Pair(typeIds.getAndIncrement(), cons)

            val type = types[cls]!!

            if (addDefaultProvider && providers[type.first] == null) {
                providers[type.first] = { vg, _ ->
                    type.second!!.newInstance(vg.context) as View
                }

            }
            return type.first
        } else {
            return prevAns.first
        }
    }


    inline fun <reified V> setProvider(noinline provider: (ViewGroup, Int) -> V) where V : View, V : GenericAdapterView<*> {
        providers[viewType<V>(false)] = provider
    }

    inline fun <reified V> provider(noinline provider: (Context) -> V) where V : View, V : GenericAdapterView<*> {
        providers[viewType<V>(false)] = { vg, _ -> provider(vg.context) }
    }

    inline fun <reified V> addProvider(noinline provider: (Context) -> V) where V : View, V : GenericAdapterView<*> {
        providers.set(viewType<V>(false)) { vg, _ -> provider(vg.context) }
    }


    inline fun <reified V, reified Model : Any> setSections(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.clear()
        addSections<V, Model>(data, extra)
    }

    inline fun <reified V, reified Model : Any> setSectionsDiffUtil(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {

        val diffCallback = MyDiffCallback(sections.map { it.data }, data.toList())
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        sections.clear()
        addSections<V, Model>(data, extra)
        diffResult.dispatchUpdatesTo(this)

    }

    fun setSectionsDiffUtil(newSections: Collection<Section<*>>) {
        val diffCallback = MyDiffCallback(sections.map { it.data }, newSections.map { it.data })
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        sections.clear()
        sections.addAll(newSections)
        diffResult.dispatchUpdatesTo(this)
    }

    inline fun <reified V, reified Model : Any> setSectionsAndNotify(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        setSections<V, Model>(data, extra)
        notifyDataSetChanged()
    }
    fun  removeItemFromSectionsAndNotify(
        index: Int,
    ) {
        sections.removeAt(index)
        notifyDataSetChanged()
    }

    inline fun <reified V, reified Model : Any> setSectionsAndNotifyRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val prevSize = itemCount
        setSections<V, Model>(data, extra)
        val newSize = itemCount
        notifyItemRangeChanged(0, newSize)
        if (prevSize > newSize) {
            notifyItemRangeRemoved(newSize, prevSize - newSize)
        }
    }


    inline fun <reified V, reified Model : Any> addSections(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val type = viewType<V>()
        sections.addAll(data.map { Section(type, it, extra) })
    }

    inline fun <reified V> addView(
    ) where V : View {
        val type = viewType<V>()
        sections.add(Section(viewType<V>(), null, null))
    }

    inline fun <reified V, reified Model : Any> addSectionsAndNotify(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyDataSetChanged()
    }

    inline fun <reified V, reified Model : Any> addSectionsAndNotifyRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyItemRangeChanged(itemCount - data.size, itemCount)
    }
    inline fun <reified V, reified Model : Any> addSectionsAndNotifyCompleteRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyItemRangeChanged(itemCount - data.size, itemCount)
    }


    inline fun <reified V, reified Model : Any?> setSection(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections[position] = Section(viewType<V>(), data, extra)
    }

    inline fun <reified V, reified Model : Any?> setSectionAndNotify(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        setSection<V, Model>(position, data, extra)
        notifyItemChanged(position)
    }

    fun updateSection(
        position: Int,
    ) {
        notifyItemChanged(position)
        Handler(Looper.getMainLooper()).post {
            notifyItemChanged(position)
        }
    }
    
    inline fun <reified V, reified Model : Any> addSection(
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.add(Section(viewType<V>(), data, extra))
    }

    inline fun <reified V, reified Model : Any> addSectionAndNotify(
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSection<V, Model>(data, extra)
        notifyItemInserted(sections.size - 1)
    }

    inline fun <reified V, reified Model : Any?> createEmptySection(
        data: Model?,
        extra: Any? = null
    ): Section<Model?> where V : View, V : GenericAdapterView<Model> =
        Section(viewType<V>(), data, extra)

    inline fun <reified V, reified Model : Any> createSection(
        data: Model,
        extra: Any? = null
    ): Section<Model> where V : View, V : GenericAdapterView<Model> =
        Section(viewType<V>(), data, extra)


    inline fun <reified V, reified Model : Any> addSection(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.add(position, Section(viewType<V>(), data, extra))
    }

    inline fun <reified V, reified Model : Any?> addEmpotySection(
        position: Int,
        data: Model? = null,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val type = viewType<V>()
        if (sections.find { it.type == type } != null) {
            sections.add(position, Section(viewType<V>(), data, extra))
            val index = sections.indexOfLast { it.type == type }
            providers.delete(index)
            sections.removeAt(index)
            notifyItemRangeChanged(index-1,1)
        } else {
            sections.add(position, Section(viewType<V>(), data, extra))
            notifyItemInserted(position)
        }
    }

    inline fun <reified V, reified Model : Any> addSectionAndNotify(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSection<V, Model>(position, data, extra)
        notifyItemInserted(position)
    }


    inline fun <reified V, reified Model : Any> createSections(
        data: Collection<Model>,
        extra: Any? = null
    ): List<Section<Model>> where V : View, V : GenericAdapterView<Model> =
        data.map { Section(viewType<V>(), it, extra) }


    fun createSection(
        cls: Class<*>,
        data: Any,
        extra: Any? = null
    ): Section<*> =
        Section(viewType(cls), data, extra)


    fun clearData() {
        sections.clear()
    }

    fun clearDataAndNotify() {
        sections.clear()
        providers.clear()
        notifyDataSetChanged()
    }

    inline fun <reified V : View> clearViews() {
        val type = viewType<V>()
        sections.removeAll { it.type == type }
    }

    inline fun <reified V : View> findIndexItem(): Int {
        val type = viewType<V>()
        var item = 0
        sections.forEachIndexed { index, section ->
            if (section.type == type) {
                item = index
            }
        }
        return item
    }

    inline fun <reified V : View> findIndexItemNew(): Int? {
        val type = viewType<V>()
        var item: Int? = null
        sections.forEachIndexed { index, section ->
            if (section.type == type) {
                item = index
            }
        }
        return item
    }

    inline fun <reified V : View> clearSectionsWithTypeAndNotify() {
        clearViews<V>()
        notifyItemRemoved(viewType<V>(false))
        providers.delete(viewType<V>(false))
    }

    inline fun <reified T> sectionsWithType(): List<Section<T>> =
        sections.mapIndexed { index, section -> section.index = index; section }
            .filter { it.data is T }.map { it as Section<T> }

}

fun AppGenericAdapter.setSectionsInViewsListAndTryToRecycle(
    parent: ViewGroup,
    lpProvider: (AppGenericAdapter.(Section<*>, Int) -> ViewGroup.LayoutParams)? = null
) {
    for (i in 0 until sections.size) {
        val section = sections[i]
        if (i < parent.childCount) {
            try {
                val child = parent.getChildAt(i) as GenericAdapterView<Any>
                child.onBind(section.data as Any, i, section.extraObject)
            } catch (e: Exception) {
                parent.removeAllViews()
                setSectionsInViewsListAndTryToRecycle(parent)
            }
        } else {
            val vh = onCreateViewHolder(parent, section.type)
            if (vh.itemView is GenericAdapterView<*>) {
                (vh.itemView as GenericAdapterView<Any>).onBind(
                    section.data!!,
                    i,
                    section.extraObject
                )
            }
            if (lpProvider != null) {
                vh.itemView.layoutParams = lpProvider(section, i)
            }
            parent.addView(vh.itemView)
        }
    }
    if (parent.childCount - sections.size > 0) {
        parent.removeViews(sections.size, parent.childCount - sections.size)
    }
}

This is a Generic adapter class you can use in all project instances of a simple adapter. you just add an item and pass to the generic class to create your list.

How to User
First of all, you must add this class to your project.

abstract class BaseCustomView<viewDataBinding : ViewDataBinding> @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {
    lateinit var binding: viewDataBinding

    init {
        this.inflate(context, attrs)
    }

    @CallSuper
    protected open fun inflate(context: Context, attrs: AttributeSet?){

        val bindingClass = javaClass.findGenericWithType<viewDataBinding>(ViewDataBinding::class.java)

        if(isInEditMode){
            if(bindingClass != null){
                val resId = bindingClass.layoutId(context)
                LayoutInflater.from(context).inflate(resId, this, true)
            }
        } else {
            binding = bindingClass?.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java)?.invoke(null, LayoutInflater.from(context), this, true) as viewDataBinding
            binding.setView(this)
        }
    }


}

after that, your item (VH), must inheritance this class like this

class YourItem @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : BaseCustomView<YouBinding>(context, attrs, defStyleAttr),
    GenericAdapterView<Model> {
    override fun onBind(model: Model, position: Int, extraObject: Any?) {
    }
}

and finally, append an item to the adapter

private val adapter = AppGenericAdapter().apply {
    provider { context ->
        YourItem (context,)// if you want to pass extra data you can pass data as arg
    }
    provider { context ->
        YourItemButton(context,)// if you want to pass extra data you can pass data as arg
    }
}

binding.recycler.adapter = adapter
adapter.addSectionsAndNotify<YourItem , Model>(data)
// you can check with if the last item add this item
adapter.addSectionsAndNotify<YourItemButton , Model>(data)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文