[Android]寿司屋で例えるRecyclerView

#RecyclerViewとは
スクロールして、ズラーーーーっと表示させるやつです。
わかりますよね？ズラー〜〜〜〜〜〜ってやつ。

まるで、回転寿司のように！
ということで、RecyclerViewを回転寿司に例えて解説していきたいと思います。

#回転寿司で例えると・・・・
###RecyclerViewは
>RecyclerView は、データに対応するビューを含む ViewGroup です。

ViewGroupとは、Viewを子として持つ親的なViewのことです。
AndroidStudioで、最初にプロジェクトを開くとactivity_mainのレイアウトファイルに、ConstraintLayoutとTextViewがあると思います。
このConstraintLayoutが、その場合ViewGroupに当たります。

ViewGroupを寿司屋（回転）の例に。
お寿司の「回転レール」に流れている「皿」を子とすると、レールは親的な意味になりますね。
イメージつきましたかね？

さて、RecyclerViewを実装するにあたって、登場人物を紹介します。

###RecyclerView(主役)
回転レール

###ViewHolder
皿

###Adapter
板前

###LayoutManager
配膳係

###onCreateViewHolder(メソッド)
皿取得

###onBindViewHolder(メソッド)
寿司握る

###getItemCount(メソッド)
皿数取得

###dataset
お寿司

#レシピ
レール作る
皿作る
板前登場
皿生成
皿数取得
寿司握る
板前指定
配膳指定

# 料理開始

どんな意味なのか、具体的に分からない部分があるかと思うので、作りながら見ていきましょう！！！
ドキュメントのコードほぼ写経する感じで作っていきます！！

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
```
ここでRecyclerViewを配置します。
当然、この時点ではお寿司屋の「回転レール」を配置しただけなので、特に何も表示されません。
というか、エラーが起きます。

```xml:recyclerview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/abstract_order"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="40sp"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
```
さて、ここで「回転レール」に乗せるものを定義します。
大事なのが、前述したとおり「皿」であること。

どういうことか説明します。

いきなりですが、回転レールの皿に乗っているものはなんですか？
そう！お寿司ですね。
しかし、この時点では、例えば「まぐろ」や「サーモン」といった具体的なネタは定義していません。
あくまで「皿」。

つまり、この時点では「回転レール」に流れる「皿」を定義していることです。
イメージつきましたかね？

お寿司屋に行ったけど、お寿司が何も乗っていないお皿が流れているイメージを持って次へ！

```kotlin:ItamaeAdapter.kt
package com.example.recyclerviewsample

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class ItamaeAdapter(private val dataset: Array<String>):  RecyclerView.Adapter<ItamaeAdapter.ViewHolder>(){

    class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
        val sushiText: TextView = view.findViewById(R.id.dish)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_item,parent,false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.sushiText.text = dataset[position]
    }

    override fun getItemCount(): Int = dataset.size

}
```
さぁ、ここが一番忙しいです。
改めて、登場人物を整理。

###RecyclerView(主役)
回転レール

###ViewHolder
皿

###Adapter
板前

###LayoutManager
配膳係

###onCreateViewHolder(メソッド)
皿取得

###onBindViewHolder(メソッド)
握る

###getItemCount(メソッド)
皿数取得

###dataset
お寿司

```kotlin
class ItamaeAdapter(private val dataset: Array<String>):  RecyclerView.Adapter<ItamaeAdapter.ViewHolder>() {
```

一行ずつ見ていきましょう。
まずは、dataset: Array<String>について。
これは、先程定義した「皿」に乗せる「お寿司」をまとめたものです。
もっというと、「回転レール」に流す「お寿司」です。
これは、`MainActivity`の方で定義しています。

そして、Adapterとは、「板前」と例えました。
つまり、「お寿司」を握る役割をしています。

`ItamaeAdapter`の中で行っている処理を簡潔に説明すると、「お寿司」を「握る」。
そして、「回転レール」に流すです。

```kotlin
    class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
        val sushiText: TextView = view.findViewById(R.id.dish)
    }
```

`ViewHolder`は、「皿」のことでした。
先程、`recyclerview_item.xml`にて「皿」のレイアウトを定義しました。
これをオブジェクトとして、つまり実際に「板前」さんが、使えるようにクラスを宣言します。

```kotlin
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_item,parent,false)
        return ViewHolder(view)
    }
```

そして、「皿取得」こと`onCreateViewHodler`メソッドによって、「皿」を返します。
その「皿」は、`onBindViewHolder`へ渡すことになります。

```kotlin
  @NonNull
        public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType);

(省略)

   public abstract void onBindViewHolder(@NonNull VH holder, int position);
```
裏のコードがこんな感じに`onCreateViewHolder`がVHとジェネリック？となっていて、onBindViewHolderの第一引数に、VH型（多分ジェネリックだと思う？けど）を受けているので多分合ってますよね。

あ、ここらへんは基本無視でいいです。
個人的な興味に付き合わせてしまってすみません！

LayoutInflaterについてですが、「おまじない」と思って大丈夫なのですが、気になる方は以前その「おまじない」について解説した記事があるので、ご参照ください。

https://qiita.com/LaO/items/cb8401510586efeba292

しかし、「お皿」については、ややこしいですね。
お寿司がお目当てなのに・・・・・。

と、ここで整理しておきましょう。
「皿」の手順は3つあります。

まずは、

###1.レイアウトを作成
`recyclerview_item.xml`にて

###2.「皿」のクラスを作成
`ViewHolder(view: View): RecyclerView.ViewHolder(view)`クラスにて

###3.「皿」を呼び出す
`onCreateViewHolder `メソッドにて

```kotlin
    override fun getItemCount(): Int = dataset.size
```
先にこっちを説明しちゃいます。
これは、後ほど出てきますが、「お寿司」ことdatasetです。
datasetと命名していますが、これは何でも良いです。
好きな名前でも、問題ありません。

`getItemCount`は、「皿数取得」ですから、「回転レール」に流す「お寿司」の皿数を取得して、次に解説するonBindViewHolderへと渡します。

```kotlin
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.sushiText.text = dataset[position]
    }
```

さぁ、こちらがお寿司を「握る」ところです。
パラメータに、「皿」ことViewHolder、そしてpositioは「お寿司」ことdatasetの要素番号ですね。

要素番号？？？と思った方いるかも知れません。

```kotlin:MainActivity.kt
package com.example.recyclerviewsample

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val sushiList = arrayOf(
            "まぐろ",
            "サーモン",
            "いくら",
            "はまち",
            "えび",
            "あなご",
            "かっぱ巻き",
            "コーン",
            "いか",
            "たこ",
            "ねぎとろ",
            "大トロ",
            "中トロ",
            "えんがわ",
            "たまご",
            "ほたて",
            "ごはだ",
            "さば"
        )
        val recyclerView = findViewById<RecyclerView>(R.id.recyclerview)
        recyclerView.adapter = ItamaeAdapter(sushiList)
        recyclerView.layoutManager = LinearLayoutManager(this)
    }
}
```

もう、`MainActivity`まで見ちゃいましょう。
`sushiList`が今回「お寿司」に当たる部分です。
これが、リスト型なので、要素番号があるわけです。

そして、要素ごとに一つ一つ、「皿」こと`ViewHolder`にセットしていくわけです。

さぁ、最後にMainActivityの閉じ括弧を除いた最後の３行の処理。
まずは、`RecyclerView`を呼び出していますね。
そして、recyclerViewのadapterに、先程作成したItamaeAdapterを代入しています。
さらに、　sushiListを引数に渡しています。
これにより、「回転レール」と「板前」と「お寿司」が繋がりました。

そして、最後の最後！！
これも、「おなじない」で良いかなと思うのですが笑。
ドキュメント内では、このように説明しています。

>レイアウト マネージャーによって、リスト内の個々の要素が配置されます。

つまり、「お寿司」を「回転レール」に並べる、「配膳係」が必要なのです！（配膳と言うのか、危うい）

そんなこんなで、イカ（以下）のように作れたかなと。

![スクリーンショット 2021-06-29 19.37.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599059/47fc51b0-2810-76aa-d619-4b2baa8d8047.png)

#写経用
写しやすいようにまとめて貼ります。
多分、まんま写しても出来上がるかなと。

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
```

```xml:recyclerview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/abstract_order"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="40sp"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
```
```kotlin:ItamaeAdapter.kt
package com.example.recyclerviewsample

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class ItamaeAdapter(private val dataset: Array<String>):  RecyclerView.Adapter<ItamaeAdapter.ViewHolder>(){

    class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
        val sushiText: TextView = view.findViewById(R.id.dish)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_item,parent,false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.sushiText.text = dataset[position]
    }

    override fun getItemCount(): Int = dataset.size

}
```
```kotlin:MainActivity.kt
package com.example.recyclerviewsample

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val sushiList = arrayOf(
            "まぐろ",
            "サーモン",
            "いくら",
            "はまち",
            "えび",
            "あなご",
            "かっぱ巻き",
            "コーン",
            "いか",
            "たこ",
            "ねぎとろ",
            "大トロ",
            "中トロ",
            "えんがわ",
            "たまご",
            "ほたて",
            "ごはだ",
            "さば"
        )
        val recyclerView = findViewById<RecyclerView>(R.id.recyclerview)
        recyclerView.adapter = ItamaeAdapter(sushiList)
        recyclerView.layoutManager = LinearLayoutManager(this)
    }
}
```
#終わりに
わかりやすいように解説したつもりが、逆にわかりにくくなってないか心配笑。
あくまで、今回のは、一つの書き方です。

「配膳係」こと`LayoutManager`も自作できたり、`GridLayoutManager `を用いると等間隔で配置したり、逆に異なる間隔で配置したりと「配膳」のバリエーションが増えたりします。
スクロールも自作リスナーで、できたりするので色々方法はあります。

しかし、今回はドキュメントのコードを真似てやってみました。

自分自身、RecyclerViewの仕組みが全く分かってない状態で、色々調べたので、至らない点があるかと思います。
そのため、毎度のことツッコミをお待ちしております。