$30 off During Our Annual Pro Sale. View Details »

RecyclerViewとGridLayoutManager について学んだ話

Shouhei Nagai
December 18, 2018
350

RecyclerViewとGridLayoutManager について学んだ話

potatotips #57

Shouhei Nagai

December 18, 2018
Tweet

Transcript

  1. RecyclerViewと GridLayoutManager について学んだ話 Shohei Nagai (@nagais) 2018/12/18 potatotips #57

  2. 自己紹介 • 永井翔平(@nagais) • Androidアプリ開発を初めて1年3ヶ月ほど • 株式会社アイスタイルにて@cosmeのAndroidアプリ開発に 携わっています • potatotipsには今回が初参加で、外部の勉強会で登壇するの

    も今回が初です 2
  3. 今日お話ししたいこと • Viewをリサイクルしながらグリッドで表示する方法 • ViewTypeを元にグリッドの分割数とレイアウトを変更する方 法 3

  4. ある時… 4

  5. こんな感じの実装依頼が • タイトル1行とアイテムを複数をセッ トとして繰り返す画面 • 1行のカラムを2つとする • タイトルとなるViewはカラム2つ分の 幅を使用する 5

    View View View View View View
  6. 何に困ったか • グリッドで表示する画面がアプリ内 になく、触ったことがなかった • GridLayoutManagerが使えそうだっ たが、1行のViewと2カラムの行数 が不規則なViewをセットで繰り返す 方法が不明だった 6

    View View View View View View View
  7. どうしたか • グリッド表示のさせ方 ◦ GridLayoutManagerをセットしたRecyclerViewを使用した • 表示するviewの数が不規則 ◦ ModelにViewTypeを持たせる •

    1行のViewと2カラムのViewの表示 ◦ GridLayoutManagerのSpanSizeLookupを使用した 7
  8. グリッド表示のさせ方 8

  9. ActivityでのRecyclerViewセッティング 9 private fun initRecyclerView () { binding.recyclerView.adapter = viewModel.customAdapter

    // 2カラム指定 val layoutManager = GridLayoutManager (this, 2) binding.recyclerView.layoutManager = layoutManager } 1. RecyclerViewのAdapterにCustomAdapterをセット 2. 2カラム指定したGridLayoutManagerのインスタンス作成 3. RecyclerViewのLayoutManagerにセット
  10. 表示するview数が不規則 10

  11. 悩んだこと 11 • 2カラムのデータが可変だったため、 セクション毎にデータをまとめて管理 したくなかった • 特定のIndexで1行のViewが挿入さ れるわけでなかった Index

    1 List Index 0 Index 4 Index 2 Index 3 Index 5 ここが可変
  12. 動的に表示位置を変更する 方法はないだろうか… 12

  13. そうだ! ModelにViewTypeを持たせよう! 13

  14. ModelにViewTypeを持たせる data class ABModel(val viewType: CustomAdapter.ViewType, val name: String, val

    imageUrl: String) 14 ViewType AとBで共通で使用できるModelにViewTypeを持たせ る ViewType A → 一行のView ViewType B → 二行のView enum class ViewType(val type: Int) { A(111), B(112) }
  15. 1行のViewと2カラムのViewの表示 15

  16. Adapter側の処理 override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerViewHolder { return

    when (viewType) { ViewType.A.type -> <ViewType Aのレイアウトを保持するViewHodlerを返却する> else -> <ViewType Bのレイアウトを保持するViewHolderを返却する> } } override fun getItemViewType(position: Int) = modelList[position].viewType.type override fun onBindViewHolder(holder: RecyclerViewHolder?, position: Int) { val model = modelList[position] when (model.viewType) { ViewType.A -> (holder?.binding as ALayoutBinding).viewModel.model = model ViewType.B -> (holder?.binding as BLayoutBinding).viewModel.model = model } } 16 1. 表示するpositionのModelが持つViewTypeを利用 2. ViewTypeに合わせて返却するHolderを変更 3. ViewTypeに合わせてModelをセットするLayout変更
  17. カラム数を動的に変更する 17 GridLayoutManagerのSpanSizeLookup()を使用して、 ViewTypeに合わせてカラム数を変更する処理を追加 private fun initRecyclerView () { binding.recyclerView.adapter

    = viewModel.customAdapter // 2カラム指定 val layoutManager = GridLayoutManager(this, 2) layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { return when (viewModel.customAdapter.getItemViewType(position)) { CustomAdapter.ViewType.A.type -> 2 else -> 1 } } } binding.recyclerView.layoutManager = layoutManager }
  18. おわりに • RecyclerViewとGridLayoutManagerを使用して複数の ViewTypeを想定した場合の実装方法を紹介しました • 普段使っているライブラリでも、知らないことはまだまだあるな と思いました • 今後は普段使っているライブラリの中を覗いたり、まだ知らな い使い方があるのではないかを常に考えたい

    18