RecyclerView Несколько ViewHolders ItemDetailsLookup - PullRequest
0 голосов
/ 20 сентября 2019

Мое окно повторного просмотра (для просмотра в чате) правильно загружает представления, но когда я нажимаю на представление, оно выдает исключение приведения:

ViewHolderReceived cannot be cast to ViewHolderSent

ViewHolders:

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
        }
    }

ItemDetailsLookup:

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 (глупо, я написал этополусонный).

Ответы [ 2 ]

1 голос
/ 20 сентября 2019

Это может быть легко решено, если вы извлекли общий метод до суперкласса или интерфейса, тогда вы сможете выполнить безопасное приведение независимо.Например:

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()
        }
    }
}
0 голосов
/ 20 сентября 2019
return if(recyclerView.getChildAdapterPosition(view) == 0){
            (recyclerView.getChildViewHolder(view) as MyAdapter.ViewHolderReceived)
                .getItemDetails()} else {
            (recyclerView.getChildViewHolder(view) as MyAdapter.ViewHolderSent)
                .getItemDetails()} // error here

Вы предполагаете, что позиция наверняка возвращает значение, к которому вы приводите.Когда вы делаете SomeValue as SomeType, вы делаете утверждение, что SomeValue наверняка является наследником SomeType.

Если вы не знаете, что это так, чего в данном случае вы не делаететак как у вас есть два возможных типа, к которым вы можете привести.Вы должны проверить, является ли тип is определенного типа, прежде чем разыграть его.

Если это не так, вы получите сообщение об ошибке cannot cast x to y

, вам следует выполнить вызовы с помощью

if(recyclerView.getChildAdapterPosition(view) == 0){
    if (recyclerView.getChildViewHolder(view) is MyAdapter.ViewHolderReceived) {
        (recyclerView.getChildViewHolder(view) as MyAdapter.ViewHolderReceived).getItemDetails()
    } else {
        (recyclerView.getChildViewHolder(view) as MyAdapter.ViewHolderSent).getItemDetails()
        (recyclerView.getChildViewHolder(view).getItemDetails
    } 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...