Master/Detail Flow + RecyclerView + GridLayoutManagerでタブレット対応でレイアウトが崩れにくいグリッド表示

#はじめに
既存のアプリをタブレット対応して下さいと言われた時にListを単純に横に伸ばしただけだと空白が広くなりすぎて見づらいとか、リスト上に文字が多く表示されてゴチャゴチャしたりとかあるかと思います。
スマホ用とタブレット用で別のlayoutを作成すれば良いのですが、どうにかして同じレイアウトで良い感じにならないかと考えた結果...

Grid表示とMaster/Detail Flowレイアウトを組み合わせたら結構いい感じになるんじゃないかと思ったので簡単なものを作ってみました:slight_smile:

#つくったもの
Gridレイアウトの横に並ぶセルの数を画面の横幅に合わせて変えただけ。

スマホ表示
![sp_ver (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172740/e18ca4d2-b9d7-fcd0-7b1a-ba462adf0146.jpeg)

タブレット
![sp_ver (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172740/2f46414a-1be6-0ec9-624e-e31635a1524c.jpeg)

#つくりかた
簡単に作る為に、Master/Detail Flowテンプレートでプロジェクトを作成
![スクリーンショット 2020-12-18 10.48.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172740/f3c9b3e1-0300-a97b-85ee-6b1ebe614261.png)

グリッド表示するのにCardViewを使用すると見た目が楽なので追加

```build.gradle
dependencies {
    //省略
    implementation 'androidx.cardview:cardview:1.0.0'
}
```
リスト表示をCardViewに変更

```item_list_content.xml
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="6dp"
    app:cardElevation="6dp"
    app:cardUseCompatPadding="true"
    app:contentPadding="8dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/id_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/text_margin"
            android:textAppearance="?attr/textAppearanceListItem"
            tools:text="no" />

        <TextView
            android:id="@+id/content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/text_margin"
            android:textAppearance="?attr/textAppearanceListItem"
            tools:text="explain" />
    </LinearLayout>
</androidx.cardview.widget.CardView>
```
/res/layout-w900dpにあるやつをlayout-w600dpにコピペしてRecyclerViewとFrameLayoutの横幅の表示をlayout_weightで1:3になるように変更
(layout-w900dpの方は1:2にになるように変更)

```layout-w600dp/item_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    android:baselineAligned="false"
    android:divider="?android:attr/dividerHorizontal"
    android:orientation="horizontal"
    android:showDividers="middle"
    tools:context=".ItemListActivity"
    android:weightSum="4">

    <androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/item_list"
        android:name="com.example.masterdetailsample.ItemListFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        app:layoutManager="LinearLayoutManager"
        tools:context="com.example.masterdetailsample.ItemListActivity"
        tools:listitem="@layout/item_list_content" />

    <FrameLayout
        android:id="@+id/item_detail_container"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3" />

</LinearLayout>
```
ItemListActivity.ktのsetupRecyclerViewのところにGridLayoutManagerでGrid表示するように設定し、spanCountを画面サイズによって変更するように追記

```ItemListActivity.kt

private fun setupRecyclerView(recyclerView: RecyclerView) {
        recyclerView.adapter = SimpleItemRecyclerViewAdapter(this, DummyContent.ITEMS, twoPane)
        val spanCount = getSpanCount()
        recyclerView.layoutManager =
            GridLayoutManager(this, spanCount, RecyclerView.VERTICAL, false)
    }

    private fun getSpanCount(): Int {
        val dMetrics = DisplayMetrics()
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
            val display = this.display;
            display?.getRealMetrics(dMetrics)
        } else {
            @Suppress("DEPRECATION")
            window.windowManager.defaultDisplay.getRealMetrics(dMetrics)
        }
        var realWidth = dMetrics.widthPixels / dMetrics.density
        return if ( realWidth >= 600 && realWidth < 900) 1 else 2
    }
```
完成:grin:

gitHub:https://github.com/iKimishima/MasterDetailGridList.git

#まとめ
これでどんな画面サイズが来ても大丈夫！

と思ったけど今回はTempleteを使用したのでMaster/Detail Flowの設定が必要なかったが、既存アプリにMaster/Detail Flowを導入するときは大変だろうなと思った冬の夜。