将通用的 RecyclerView 适配器转换为 Kotlin



目前,我有一个要填充的列表,但列表项可以有不同的数据。 我有两个数据类,为了适应RecyclerView,我有两个不同的ViewHolder扩展了一个基本的基本ViewHolder。 由于不同的布局用于不同的数据类,因此需要不同的 ViewHolder。

我已将视图持有者转换为 Kotlin,但是适配器有问题。

Kotlin 中的基本 ViewHolder:

abstract class BaseViewHolder<T> internal constructor(view: View) : RecyclerView.ViewHolder(view) {
abstract fun bind(item: T)
}

在 Kotlin 中实现基本 ViewHolder 的 ViewHolder:

class StandardViewHolder(view: View): BaseViewHolder<Standard>(view) {
private val _eventView      : TextView = view.findViewById(R.id.eventTextView)
private val _dateView       : TextView = view.findViewById(R.id.dateTextView)
override fun bind(item: Standard) {
_eventView.text     = item.event
_dateView.text      = item.date.toString()
}
}

在 Java 中,我可以创建一个使用这些 ViewHolder 的适配器:

public class ListAdapter extends RecyclerView.Adapter<BaseViewHolder> {
private List<Object> _items;
private Context _context;
public ListAdapter(List<Object> items, Context context){
_items      = items;
_context    = context;
}
@NonNull
@Override
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if(viewType == R.layout.item_standard){
return new StandardViewHolder(LayoutInflater.from(_context).inflate(
R.layout.item_standard, parent, false));
}
return new AdvancedViewHolder(LayoutInflater.from(_context).inflate(
R.layout.item_advanced, parent, false));
}
@Override
@SuppressWarnings("unchecked")
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
holder.bind(_items.get(position));
}
@Override
public int getItemCount() {
return _items.size();
}
@Override
public int getItemViewType(int position) {
if(_items.get(position) instanceof Standard){
return R.layout.item_standard;
}
return R.layout.item_advanced;
}
}

但是,如果我将其转换为 Kotlin,则会在holder.bind上出现错误,即:

投影外类型"BaseViewHolder<*>"禁止使用"公共" 抽象趣味绑定(项目:T('

class ListAdapter(private val _items: List<Any>, private val _context: Context) : RecyclerView.Adapter<BaseViewHolder<*>>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
return if (viewType == R.layout.item_standard) {
StandardViewHolder(LayoutInflater.from(_context).inflate(
R.layout.item_standard, parent, false))
} else {
AdvancedViewHolder(LayoutInflater.from(_context).inflate(
R.layout.item_advanced, parent, false))
}
}
override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) = holder.bind(_items[position])
override fun getItemCount() = _items.size
override fun getItemViewType(position: Int): Int {
return if (_items[position] is Standard) {
R.layout.item_standard
} else {
R.layout.item_advanced
}
}
}

如何在 Kotlin 中使用这些通用 ViewHolder?

问题是,即使您知道绑定的项与为其创建的 ViewHolder 的类型匹配,也无法在编译时证明它,因此编译器会对您大喊大叫。你不能在BaseViewHolder<*>上调用bind,因为这样参数必须是不可能发生的*类型。你需要的东西BaseViewHolder<Any>但你不能使适配器RecyclerView.Adapter<BaseViewHolder<Any>>,因为这会破坏onCreateViewHolder。我已经尝试过BaseViewHolder<out Any>,这也不起作用。

所以这是你做的:使用BaseViewHolder<*>,然后在内部onBindViewHolder将其投射到BaseViewHolder<Any>.编译器会抱怨">嘿!这是一个未经检查的演员阵容!你不应该那样做!",所以告诉它闭嘴@Suppress("UNCHECKED_CAST").

class ListAdapter(
private val _items: List<Any>,
private val _context: Context
) : RecyclerView.Adapter<BaseViewHolder<*>>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
return if (viewType == R.layout.item_standard) {
StandardViewHolder(LayoutInflater.from(_context).inflate(
R.layout.item_standard, parent, false))
} else {
AdvancedViewHolder(LayoutInflater.from(_context).inflate(
R.layout.item_advanced, parent, false))
}
}
@Suppress("UNCHECKED_CAST")
override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
(holder as BaseViewHolder<Any>).bind(_items[position])
}
override fun getItemCount() = _items.size
override fun getItemViewType(position: Int): Int {
return if (_items[position] is Standard) {
R.layout.item_standard
} else {
R.layout.item_advanced
}
}
}

不错的一个...实际上,我对此进行了一些返工,看看我做了什么。 我已经使它成为有史以来最动态的适配器。

https://medium.com/@sandipsavaliya/tired-with-adapters-4240e5f45c24

对于"通用回收器"视图,请使用以下代码:

步骤 1:使用 RecyclerView.Adapter(( 扩展适配器 例如

class MyAdapter(private val recentList: ArrayList<CollectionModel>) :
RecyclerView.Adapter<**RecyclerView.ViewHolder**>() {
}

步骤 2:为所有视图设置视图类型 例如

override fun getItemViewType(position: Int): Int {
return if (recentList[position].type == 0) CollectionModel.COLLECTION_HEADER else CollectionModel.COLLECTION_DETAIL
}

第 3 步:在 onCreateViewHolder 中定义正确的视图和 ViewHolder 例如

if (viewType == CollectionModel.COLLECTION_HEADER) {
val view = LayoutInflater.from(parent.context).inflate(R.layout.signle_row_header, parent, false)
return HeaderCollectionHolder(view)
} else {
val view = LayoutInflater.from(parent.context).inflate(R.layout.single_row_collection_history, parent, false)
return DetailHolder(view)
}

第 4 步:在 onBindViewHolder 内部根据视图类型绑定数据,并使用as关键字将视图持有者转换为类型 例如

val collectionModel = recentList[position]
if (recentList[position].type == CollectionModel.COLLECTION_HEADER) {
(holder as HeaderCollectionHolder).apply {
header.text = collectionModel.date
}
} else {
(holder as DetailHolder).apply {
name.text = collectionModel.name
phone.text = collectionModel.phone
collectedAmount.text = collectionModel.lastCollectAmount.toInt().toString()
balanceAmount.text = collectionModel.pendingBalance.toInt().toString()
Utils.setImage(collectionModel.picUrl, imageView)
}
}

第 5 步:创建两个视图持有者类,如下所示:

inner class DetailHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var name: TextView = itemView.findViewById(R.id.name)
var phone: TextView = itemView.findViewById(R.id.phone)
var collectedAmount: TextView = itemView.findViewById(R.id.total_amount)
var balanceAmount: TextView = item`enter code here`View.findViewById(R.id.balance_amount)
var imageView: CircularImageView = itemView.findViewById(R.id.user_image)
}
inner class HeaderCollectionHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val header: TextView = itemView.findViewById(R.id.text)
}

就是这样。

最新更新