首页 > 解决方案 > RecyclerView Multiple ViewHolders ItemDetailsLookup

问题描述

我的 recyclerview (用于聊天视图)正确加载视图,但是当我点击视图时,它会引发强制转换异常:

ViewHolderReceived cannot be cast to ViewHolderSent

视图持有者:

class ViewHolderReceived(val view: View) : RecyclerView.ViewHolder(view) {
        fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long> =
            object : ItemDetailsLookup.ItemDetails<Long>() {
                override fun getPosition(): Int = adapterPosition
                override fun getSelectionKey(): Long? = itemId
                override fun inSelectionHotspot(e: MotionEvent): Boolean {
                    return true
                }
            }

        fun bind(isSelected: Boolean = false) {
            itemView.isSelected = isSelected
        }
    }

    //#########################################################################

    class ViewHolderSent(val view: View) : RecyclerView.ViewHolder(view) {
        fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long> =
            object : ItemDetailsLookup.ItemDetails<Long>() {
                override fun getPosition(): Int = adapterPosition
                override fun getSelectionKey(): Long? = itemId
                override fun inSelectionHotspot(e: MotionEvent): Boolean {
                    return true
                }
            }

        fun bind(isSelected: Boolean = false) {
            itemView.isSelected = isSelected
        }
    }

ItemDetails查找:

class MyItemDetailsLookup(private val recyclerView: RecyclerView) :
    ItemDetailsLookup<Long>() {
    override fun getItemDetails(event: MotionEvent): ItemDetails<Long>? {
        val view = recyclerView.findChildViewUnder(event.x, event.y)
        if (view != null) {
            return if(recyclerView.getChildAdapterPosition(view) == 0){
                (recyclerView.getChildViewHolder(view) as MyAdapter.ViewHolderReceived)
                    .getItemDetails()} else {
                (recyclerView.getChildViewHolder(view) as MyAdapter.ViewHolderSent)
                    .getItemDetails()} // error here
        }
        return null
    }
}

无论点击哪个视图,它都会引发相同的错误(对于 ViewHolderReceived 或 ViewHolderSent),但会以正确的顺序正确绑定它们。

注意:如果我在点击任何已发送的视图后点击收到的视图,它只会引发错误,反之亦然

找到解决方案:问题出在 recyclerView.getChildAdapterPosition(我傻了,半睡半醒)。

标签: androidkotlinandroid-recyclerview

解决方案


如果您将共享方法提取到超类或接口,这可以很容易地解决,那么无论如何您都可以执行安全转换。例如:

abstract class SelectableViewHolder(val view: View) : RecyclerView.ViewHolder(view){
    fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long> =
        object : ItemDetailsLookup.ItemDetails<Long>() {
            override fun getPosition(): Int = adapterPosition
            override fun getSelectionKey(): Long? = itemId
            override fun inSelectionHotspot(e: MotionEvent): Boolean {
                return true
        }
    }

    open fun bind(isSelected: Boolean = false) {
        itemView.isSelected = isSelected
    }
}

class ViewHolderReceived(view: View) : SelectableViewHolder(view) {
    override fun bind(isSelected: Boolean = false) {
        super.bind(isSelected)
        // anything else specific for received viewholder
    }
}

class ViewHolderSent(view: View) : SelectableViewHolder(view) {
    override fun bind(isSelected: Boolean = false) {
        super.bind(isSelected)
        // anything else specific for sent viewholder
    }
}

然后查找很容易:

class MyItemDetailsLookup(private val recyclerView: RecyclerView) : ItemDetailsLookup<Long>() {
    override fun getItemDetails(event: MotionEvent): ItemDetails<Long>? {
        return recyclerView.findChildViewUnder(event.x, event.y)?.let {
            (recyclerView.getChildViewHolder(it) as SelectableViewHolder).getItemDetails()
        }
    }
}

推荐阅读