RecyclerView+ListAdapterを使用したチャットビュー(複数のViewHolder)


ドライバ環境
  • 最小sdk:23
  • 現在のsdk:302 4579182
  • 言語:Kotlin
  • fastキャンパス授業では,中古取引アプリを作成し,チャットルームの実習を実現した.
    教室では、チャットを送信するユーザが誰であろうと、右側でしかチャットレコードを送信しないため、機能をさらに改善するために、実際に使用しているチャットアプリケーションのようにユーザ:右側、相手:左側を実現する.

    まずやってみよう


    現在のユーザのIDは、
  • Adapterのパラメータで取得される.
  • でカスタマイズされたViewHolderでは、パラメータとして受信されたidがバインドされたidと一致する場合、idのみが非表示になります.
  • に一致しない場合、ConstraintLayout.LayoutParamsでビューを1つずつ調整しました.
  • 実施後も、初期のRecyclerViewは正常に動作します.
    メッセージを送ると、相手のチャット履歴のIDがいつも消えてしまう話題が発生します.
    むしろ2つのXMLファイルで皆さんに見せたいときに適当に噴き出して、グーグルの力を借りました.

    もう少しViewHolderを入れてもらえますか?


    幸いなことにMediaではRecyclerViewのViewHolderを拡張して実現😂
    以下のサイトはソースチャネルです.詳細な説明やその他のホットスポットがあれば、必ず入ってください.
    Multiple-view-holderを参照

    コードを導入する前に...


  • 私のコードではRecyclerview.AdapterではなくListAdapterですが、ListAdapterの2番目のGenericタイプはView Holderを指定できると思います.

  • onCreateView Holderは、パラメータを使用してView GroupとView Typeを表しますが、ほとんどがRecyclerViewを実現するために単一XMLを使用しているため、View Typeを使用する必要はありません.
  • 1.getItemViewメソッドの作成と使用

    override fun getItemViewType(position: Int): Int {
            return super.getItemViewType(position)
    }
    これは、特定のリストのアイテムにtypeを設定するのと同じです.
    Intを返しますので、初期化は次のようになります.
    companion object {    
            private const val MY_CHAT = 1
            private const val OTHER_CHAT = 2
        }
    override fun getItemViewType(position: Int): Int {
            return if (auth == currentList[position].senderId)
                MY_CHAT
            else OTHER_CHAT
        }
    authは、アダプタからパラメータとして受信された現在のユーザ(私)idである.
    ListAdapterが提供するcurrentListを使用して、ビューの位置を指定するsenderIdがauthと同じであれば、右側に描画します!そうでなければ相手の絵を左側に描きます!に表示されます.

    2.2つのViewHolder(私、相手)を作成


    onCreateViewHolderは、2つのViewHolderを返さなければなりません.
    inner class MyChatItemViewHolder(private val binding: ItemChatBinding) :
            RecyclerView.ViewHolder(binding.root) {
            fun bind(chat: ChatItem) {
                val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
                val date = Date(chat.time)
                binding.messageTextView.text = chat.message
                binding.timeTextView.text = dateFormat.format(date)
            }
        }
    
    inner class OtherChatItemViewHolder(private val binding: ItemOtherChatBinding) :
           	RecyclerView.ViewHolder(binding.root) {
            fun bind(chat: ChatItem) {
                val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
                val date = Date(chat.time)
                binding.senderTextView.text = chat.senderId
                binding.messageTextView.text = chat.message
                binding.timeTextView.text = dateFormat.format(date)
            }
        }
    bindingを練習している段階なので、ViewBindingを適用しました.
    アダプターで使われていて、とても清潔できれいです👍🏻

    3.onCreateViewHolderでViewTypeを使う

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            return if(viewType == MY_CHAT) {
                ChatItemViewHolder(
                    ItemChatBinding.inflate(LayoutInflater.from(parent.context), parent, false))
            } else {
                ChatItem2ViewHolder(
                    ItemOtherChatBinding.inflate(LayoutInflater.from(parent.context), parent, false))
            }
        }

    4.onBindViewHolderの作成

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            if(getItemViewType(position) == MY_CHAT) {
                (holder as MyChatItemViewHolder).bind(currentList[position])
            } else {
                (holder as OtherChatItemViewHolder).bind(currentList[position])
            }
        }
    ViewHolderの戻り型はRecylcerView.ViewHolderであるため、asキーワードで変換される.特定のビュー領域を入れると、他のビュー領域は使用できません.

    以上のように、形状を変えることで簡単に解決できます!


    c.f.)ListAdapaterのGenericタイプ

    ListAdapter<ChatItem, RecyclerView.ViewHolder>(diffUtil)

    振り返る


    自分の実践では、RecyclerViewをよりよく使用し、拡張性を実現する方法を理解しているようです.
    やはり自分で改善事項をどんどん考えて、もっと良い方向があれば、自分でいろいろな方法を試して、だめなら、他の方法を探して成長して、大きな助けになります.

    完全なコード

    class ChatItemAdapter(
        private val auth: String
    ) : ListAdapter<ChatItem, RecyclerView.ViewHolder>(diffUtil) {
        inner class MyChatItemViewHolder(private val binding: ItemChatBinding) :
            RecyclerView.ViewHolder(binding.root) {
            fun bind(chat: ChatItem) {
                val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
                val date = Date(chat.time)
                binding.messageTextView.text = chat.message
                binding.timeTextView.text = dateFormat.format(date)
            }
        }
    
        inner class OtherChatItemViewHolder(private val binding: ItemOtherChatBinding) :
            RecyclerView.ViewHolder(binding.root) {
            fun bind(chat: ChatItem) {
                val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
                val date = Date(chat.time)
                binding.senderTextView.text = chat.senderId
                binding.messageTextView.text = chat.message
                binding.timeTextView.text = dateFormat.format(date)
            }
    
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            return if(viewType == MY_CHAT) {
                MyChatItemViewHolder(
                    ItemChatBinding.inflate(LayoutInflater.from(parent.context), parent, false))
            } else {
                OtherChatItemViewHolder(
                    ItemOtherChatBinding.inflate(LayoutInflater.from(parent.context), parent, false))
            }
        }
        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            if(getItemViewType(position) == MY_CHAT) {
                (holder as MyChatItemViewHolder).bind(currentList[position])
            } else {
                (holder as OtherChatItemViewHolder).bind(currentList[position])
            }
        }
    
        override fun getItemViewType(position: Int): Int {
            return if (auth == currentList[position].senderId)
                MY_CHAT
            else OTHER_CHAT
        }
    
        companion object {
            val diffUtil = object : DiffUtil.ItemCallback<ChatItem>() {
                override fun areItemsTheSame(oldItem: ChatItem, newItem: ChatItem): Boolean {
                    return oldItem == newItem
                }
    
                override fun areContentsTheSame(oldItem: ChatItem, newItem: ChatItem): Boolean {
                    return oldItem == newItem
                }
            }
            private const val MY_CHAT = 1
            private const val OTHER_CHAT = 2
        }
    }

    実行画面