通用RecyclerView适配器

时间:2018-01-26 23:51:26

标签: android android-recyclerview kotlin recycler-adapter recyclerview-layout

我希望通用RecyclerView能够重用它。就我而言,我有两个模型:CategoryImagesCategory。在尝试添加constructor()时,会出现以下错误。我知道第二个是因为它理解主要和辅助构造函数是相同的。

有可能做这种事吗?如果,那怎么样?如果没有 - 谢谢。

enter image description here

以下是CategoryImage

class CategoryImage {
   @SerializedName("url")
   private var url: String? = null
       fun getUrl(): String? {
       return url
   }
}

这是Category

class Category {
    @SerializedName("_id")
    var id: String? = null
    @SerializedName("name")
    var name: String? = null
    @SerializedName("__v")
    var v: Int? = null
    @SerializedName("thumbnail")
    var thumbnail: String? = null
}

以下是RecyclerViewAdapter构造函数的一部分:

class RecyclerViewAdapter(var arrayList: ArrayList<CategoryImage>?, var fragment: Int): RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() {
     constructor(arrayList: ArrayList<Category>, fragment: Int): this(arrayList, fragment)
}

4 个答案:

答案 0 :(得分:2)

  

我希望通用RecyclerView能够重复使用它。

这是一个很好的意图,那么为什么你还没有制作适配器generic

我认为你可以采用Arman Chatikyan在this blog post中概述的方法。在应用了一些Kotlin魔法之后,您只需要按照以下代码行来设置RecyclerView

recyclerView.setUp(users, R.layout.item_layout, {
    nameText.text = it.name
    surNameText.text = it.surname
})

如果您需要处理RecyclerView项目的点击次数:

recyclerView.setUp(users, R.layout.item_layout, {
    nameText.text = it.name
    surNameText.text = it.surname
}, {
    toast("Clicked $name")
})

现在RecyclerView的适配器是通用的,您可以在setup()方法的第一个参数中传递任何模型的列表。

在本节中,我将从博客文章中复制粘贴来源,以避免外部来源弃用。

fun <ITEM> RecyclerView.setUp(items: List<ITEM>,
                              layoutResId: Int,
                              bindHolder: View.(ITEM) -> Unit,
                              itemClick: ITEM.() -> Unit = {},
                              manager: RecyclerView.LayoutManager = LinearLayoutManager(this.context)): Kadapter<ITEM> {
  return Kadapter(items, layoutResId, {
    bindHolder(it)
  }, {
    itemClick()
  }).apply {
    layoutManager = manager
    adapter = this
  }
}

class Kadapter<ITEM>(items: List<ITEM>,
                     layoutResId: Int,
                     private val bindHolder: View.(ITEM) -> Unit)
  : AbstractAdapter<ITEM>(items, layoutResId) {

  private var itemClick: ITEM.() -> Unit = {}

  constructor(items: List<ITEM>,
              layoutResId: Int,
              bindHolder: View.(ITEM) -> Unit,
              itemClick: ITEM.() -> Unit = {}) : this(items, layoutResId, bindHolder) {
    this.itemClick = itemClick
  }

  override fun onBindViewHolder(holder: Holder, position: Int) {
    holder.itemView.bindHolder(itemList[position])
  }

  override fun onItemClick(itemView: View, position: Int) {
    itemList[position].itemClick()
  }
}

abstract class AbstractAdapter<ITEM> constructor(
    protected var itemList: List<ITEM>,
    private val layoutResId: Int)
  : RecyclerView.Adapter<AbstractAdapter.Holder>() {

  override fun getItemCount() = itemList.size

  override fun onCreateViewHolder(parent: ViewGroup,
                                  viewType: Int): Holder {
    val view = LayoutInflater.from(parent.context).inflate(layoutResId, parent, false)
    return Holder(view)
  }

  override fun onBindViewHolder(holder: Holder, position: Int) {
    val item = itemList[position]
    holder.itemView.bind(item)
  }

  protected abstract fun onItemClick(itemView: View, position: Int)

  protected open fun View.bind(item: ITEM) {
  }

  class Holder(itemView: View) : RecyclerView.ViewHolder(itemView)
}

答案 1 :(得分:1)

假设CategoryImage表示带有图片的Category

你可以用继承来表达这种关系:

open class Category(
        val name: String
)
class CategoryImage(
        name: String,
        val image: String
) : Category(name)

class RecyclerViewAdapter(
        val arr: List<Category>,
        val fragment: Int
) {
    fun bind(i: Int) {
        val item = arr[i]
        val name: String = item.name
        val image: String? = (item as? CategoryImage)?.image
    }
}

另一个选择它有一个共同的界面(删除那个丑陋的演员):

interface CategoryLike {
    val name: String
    val image: String?
}

class Category(
        override val name: String
) : CategoryLike {
    override val image: String? = null
}

class CategoryImage(
        override val name: String,
        override val image: String
) : CategoryLike

class RecyclerViewAdapter(private var arr: List<CategoryLike>, var fragment: Int) {
    fun bind(i: Int) {
        val item = arr[i]
        val name: String = item.name
        val image: String? = item.image
    }
}

在这两种情况下,以下工作(只是为了看它可以编译):

fun testCreation() {
    val cats: List<Category> = listOf()
    val catImages: List<CategoryImage> = listOf()
    RecyclerViewAdapter(cats, 0)
    RecyclerViewAdapter(catImages, 0)
}

提示:不要使用ArrayListListlistOf(...))或MutableListmutableListOf(...))应该足够了满足您的所有需求。

提示:尽可能多地使用val,这有助于防止出错。

愿望:下次还请以可复制的形式(不是屏幕截图)包含代码的某些相关部分,因此我们无需重新输入代码并拥有更多上下文。见https://stackoverflow.com/help/mcve

答案 2 :(得分:0)

一种“糟糕”的做法是简单地让1个构造函数获取对象的ArrayList并对对象执行instanceof

答案 3 :(得分:0)

两种方法都具有相同的签名,因为类型参数不被视为不同的类型(对于Java虚拟机,它们都只是ArrayList s)。您还需要了解类型擦除。