Edited at

RecyclerViewでセルごとに異なるレイアウトを適用する

More than 3 years have passed since last update.

あんまりRecyclerView使う機会が無かったんですけど仕事で触る機会があったのでめも。

AdapterのgetItemViewTypeをオーバーライドしてデータに応じたViewTypeを返してあげるとレイアウトを使い分けることが出来ます。enum使うと綺麗に書ける感じですね。

下の例はItemEntityを継承した3種類のクラスに応じたレイアウトを表示するサンプルです。なお仕事では今のとこKotlinで書いてるのでサンプルもKotlinです。


CustomAdapter.kt

class CustomAdapter(context: Context,

val itemList: MutableList<ItemEntity>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

enum class ViewType(val id: Int) {
HOGE(0) {
override fun createViewHolder(inflater: LayoutInflater, viewGroup: ViewGroup?): RecyclerView.ViewHolder {
// タイプに応じたViewHolderを返す
return HogeViewHolder (inflater.inflate(R.layout.adapter_row_hoge, viewGroup, false))
}

override fun bindViewHolder(holder: RecyclerView.ViewHolder, itemEntity: ItemEntity) {
holder as HogeViewHolder
// Viewにそれぞれのデータを表示(以下略)
}
},
FUGA(1) {
override fun createViewHolder(inflater: LayoutInflater, viewGroup: ViewGroup?): RecyclerView.ViewHolder {
return FugaViewHolder (inflater.inflate(R.layout.adapter_row_fuga, viewGroup, false))
}

override fun bindViewHolder(holder: RecyclerView.ViewHolder, itemEntity: ItemEntity) {
holder as FugaViewHolder
// Viewにそれぞれのデータを表示(以下略)
}
},
PIYO(2) {
override fun createViewHolder(inflater: LayoutInflater, viewGroup: ViewGroup?): RecyclerView.ViewHolder {
return PiyoViewHolder (inflater.inflate(R.layout.adapter_row_piyo, viewGroup, false))
}

override fun bindViewHolder(holder: RecyclerView.ViewHolder, itemEntity: ItemEntity) {
holder as PiyoViewHolder
// Viewにそれぞれのデータを表示(以下略)
}
};

companion object {
fun forId(id: Int): ViewType {
for (viewType: ViewType in values()) {
if (viewType.id == id) {
return viewType
}
}
throw AssertionError("no enum found for the id. you forgot to implement?")
}
}

abstract fun createViewHolder(inflater: LayoutInflater, viewGroup: ViewGroup?): RecyclerView.ViewHolder

abstract fun bindViewHolder(holder: RecyclerView.ViewHolder, itemEntity: ItemEntity)
}

companion object {

// レイアウトに応じたViewHolderを作る。KotterKnifeを使うとBindが楽
private class HogeViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView) {
val imageHoge: ImageView by bindView(R.id.adapter_row_hoge_image)
val textHoge: TextView by bindView(R.id.adapter_row_hoge_text)
}

private class FugaViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView) {
val imageFuga: ImageView by bindView(R.id.adapter_row_fuga_image)
val textFuga: TextView by bindView(R.id.adapter_row_fuga_text)
}

private class PiyoViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView) {
val imagePiyo: ImageView by bindView(R.id.adapter_row_piyo_image)
val textPiyo: TextView by bindView(R.id.adapter_row_piyo_text)
}
}

private val inflater = LayoutInflater.from(context)

// Viewを作る時に呼ばれる
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder? {
return ViewType.forId(viewType).createViewHolder(inflater, parent)
}

// ViewにデータをBindする時に呼ばれる
override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
holder ?: return
val item = itemList[position]
ViewType.forId(holder.itemViewType).bindViewHolder(holder, item)
}

override fun getItemCount(): Int {
return itemList.size
}

// 型に応じたViewTypeを返す
override fun getItemViewType(position: Int): Int {

val item = itemList[position]

return when (item) {
is HogeItemEntity -> {
ViewType.HOGE.id
}
is FugaItemEntity -> {
ViewType.FUGA.id
}
is PiyoItemEntity -> {
ViewType.PIYO.id
}
else -> {
throw AssertionError("no enum found for the id. you forgot to implement?")
}
}
}
}