RecyclerViewはアイテムのレイアウトをアイテム毎に変更できます。その時に使う値がViewTypeです。
ViewTypeでアイテムのレイアウトを変更する方法を紹介します。
アイテムのレイアウトを変更する方法
レイアウトを変更したい場面
図はチャット風画面です。
チャットの画面は「左寄りが自分」で「右寄りが会話の相手」になります。
1つの会話が1行で表現されていて、下方向に一覧表示されていきます。
会話は発言者の画像と発言内容で構成されます。
これをRecyclerViewで表現すると…
アイテムのレイアウトがアイテム毎に変更できれば、チャット風画面がRecyclerViewで表現できます。
レイアウトを変更する方法
RecyclerViewはアイテムのレイアウトをアイテム毎に変更できます。元から変更する仕組みを持っています。
RecyclerViewを実装する時にカスタムAdapterを作りますが、その時にオーバーライドするonCreateViewHolder( )の引数にviewTypeがあります。このviewTypeがレイアウトを変更する仕組みです。
方法は図に示す通りです。
onCreateViewHolder( )でviewTypeを参照して、アイテムのViewを作成する時に使用するレイアウト(R.layout.XXXX)を切り替えればよいわけです。
アイテムのレイアウトを変更する例
ViewTypeでアイテムのレイアウトを変更する例です。
重要な点は2つです。
1つ目は、getItemViewType( )の実装とonCreateViewHolder( )のレイアウトの切り替え部分です。これは前章の「レイアウトを変更する方法」で説明した通りです。アイテムデータ(データクラスChat)内にViewTypeを持たせています。
2つ目は、ジェネリクスへ受け渡すタイプにRecyclerView.ViewHolder(スーパークラス)を用いている部分です。これはSendViewHolderとRecvViewHolder(サブクラス)の2つを引数で受けるためです。よって、onBindViewHolder( )でキャストが必要になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | internal const val VIEWTYPE_SEND = 0 // 送信、左寄りのレイアウト internal const val VIEWTYPE_RECV = 1 // 受信、右寄りのレイアウト class ChatAdapter(var chats: Array<Chat>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { // ----- 会話データ ---------------------------------------------- data class Chat( val type: Int = VIEWTYPE_SEND, val who: Bitmap?, val word: String?) // ----- ビューホルダー ------------------------------------------ inner class SendViewHolder(view: View) : RecyclerView.ViewHolder(view) { val imgLeft = view.findViewById<ImageView>(R.id.imgLeft) val txtLeft = view.findViewById<TextView>(R.id.txtLeft) } inner class RecvViewHolder(view: View) : RecyclerView.ViewHolder(view) { val imgRight = view.findViewById<ImageView>(R.id.imgRight) val txtRight = view.findViewById<TextView>(R.id.txtRight) } // ----- アダプター本体 ------------------------------------------ override fun getItemCount() = chats.size override fun getItemViewType(position: Int) = chats[position].type override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : RecyclerView.ViewHolder { val _inflater = LayoutInflater.from(parent.context) return when(viewType) { VIEWTYPE_SEND -> SendViewHolder(_inflater.inflate(R.layout.item_l, parent, false )) VIEWTYPE_RECV -> RecvViewHolder(_inflater.inflate(R.layout.item_r, parent, false )) else -> SendViewHolder(_inflater.inflate(R.layout.item_l, parent, false )) } } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when(getItemViewType(position)) { VIEWTYPE_SEND -> { if (holder is SendViewHolder) { // スマートキャスト chats[position].who?.let { holder.imgLeft.setImageBitmap(it) } chats[position].word?.let { holder.txtLeft.text = it } } } VIEWTYPE_RECV -> { if (holder is RecvViewHolder) { // スマートキャスト chats[position].who?.let { holder.imgRight.setImageBitmap(it) } chats[position].word?.let { holder.txtRight.text = it } } } else -> {} } } } |
関連記事: