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( )でキャストが必要になります。
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 -> {}
}
}
}

関連記事:
