【Kotlin】RecyclerViewでリストを表示する

##はじめに
今までRecyclerViewは複雑そうだと思って敬遠してたのですが、使ってみると意外と簡単かつ使い勝手も良さそうでしたので、忘れないうちまとめておこうと思います。
RecyclerViewの記事は他にも沢山あるので今更感が強いかもですが、私自身初学者ということもあり少し分かりづらい部分もあった為、同じような初学者向けに自分なりに分かりやすく書いてみようと思います。
なお、RecyclerViewそのものについての説明は割愛します。
それと、間違い等がございましたらご指摘頂けると嬉しいです。
##下準備
サポートライブラリを追加する必要がありますので、build.gradle(appのほう)のdependencies内に追加します。

```kotlin:build.gradle(Module.app)
dependencies {
         implementation 'androidx.recyclerview:recyclerview:1.1.0'//これを追加
}
```
##構成
先にどのような構成か書いておきます。
-MainActivity.kt　　　:リストを表示するアクティビティ
-activity_main.xml　　　:メインアクティビティ用
-item.xml　　　:リストのアイテム１つ分のレイアウト
-ItemData.kt　　　:リストのアイテム１つ分が持っている変数
-CustomAdapter.kt　　　:アダプター(今回はviewHolderを内装します)

##レイアウト
アクティビティにはとりあえずリストのみ表示させます。

```xml:activity_main.xml
<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/recyclerListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
```
item.xmlはリストに表示するアイテム１つ分のレイアウトです。
今回はファイル名とファイルの更新日を表示しようと思います。

```xml:item.xml
<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="wrap_content"
    android:background="@color/colorBackground">

    <TextView
        android:id="@+id/list_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/list_time"
        android:layout_marginStart="20dp"
        android:layout_marginTop="15dp"
        android:layout_marginBottom="15dp"
        android:text="Name"
        android:textSize="15sp"
        android:textColor="@color/colorText"/>
    <TextView
        android:id="@+id/list_time"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="5dp"
        android:text="Time"
        android:textSize="12sp"
        android:textColor="@color/colorText"/>

</androidx.constraintlayout.widget.ConstraintLayout>
```
レイアウト自体はLinearLayoutでもなんでも平気だと思います。

##アイテム１つ分のデータ
```kotlin:ItemData.kt
class ItemData {
    var nameStamp:String = ""
    var timeStamp:String = ""
}
```
リストには表示させない変数があってもオッケーです。

##カスタムアダプターの実装
CustomViewHolderクラスは別ファイルにしてもいいみたいです。
onCreateViewHolder()とgetItemCount()とonBindViewHolder()をオーバーライドしなくてはいけないみたい。
getItemCount()でリストのアイテム数を返してonCreateViewHolder()でアイテム数分のホルダーを作ってる感じなんですかね？
インターフェースやらリスナーやらは必要な場合のみ書きます。

```kotlin:CustomAdapter.kt
class CustomAdapter(private val list: List<ItemData>):RecyclerView.Adapter<CustomAdapter.CustomViewHolder>() {

    lateinit var listener:OnItemClickListener

    class CustomViewHolder(val view: View):RecyclerView.ViewHolder(view){
        val nameView:TextView = view.findViewById(R.id.list_name)
        val timeView:TextView = view.findViewById(R.id.list_time)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        val item = layoutInflater.inflate(R.layout.item_list,parent, false)
        return CustomViewHolder(item)
    }

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

    override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
        //holderにItemDataのnameStampとtimeStampをセットする
        holder.nameView.text = list[position].nameStamp
        holder.timeView.text = list[position].timeStamp
        holder.itemView.setOnClickListener {
            listener.onItemClickListener(it,list[position])
        }
    }

    //インターフェースをつくる
    interface OnItemClickListener{
        fun onItemClickListener(view:View,itemData:ItemData)
    }

    fun setOnItemClickListener(listener: OnItemClickListener){
        this.listener = listener
    }
}
```
##アクティビティにセットする
今回はsavePathに保存されているファイルをリスト表示してみます。

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setList()
    }

    private fun setList(){
        val recyclerView = findViewById(R.id.recyclerListView)
        val adapter = CustomAdapter(createList())//リストをわたします
        recyclerView.setHasFixedSize(true)

        val itemBreak = DividerItemDecoration(this,DividerItemDecoration.VERTICAL)//区切り線、必要あれば。
        recyclerView.addItemDecoration(itemBreak)

        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = adapter

        adapter.setOnItemClickListener(object:CustomAdapter.onItemClickListener{
            override fun onItemClickListener(view: View, itemData: ItemData) {
                //クリック時
                Log.d("TapItem",itemData.nameStamp + itemData.timeStamp)
            }
        })
    }

    private fun createList():List<ItemData>{
        //CustomAdapterにわたすリストを作ります
        val dataList = mutableListOf<ItemData>()
        val savePath = ""//保存先のパス、適時変更等してください。
        val files = File(savePath).listFiles()
        val sdf = SimpleDateFormat("yyyy/MM/dd/HH:mm:ss")//更新日用のフォーマット

        for (i in files.indices){
            val fileName = files[i].name//ファイル名
            val lastMod = files[i].lastModified()//更新日
            val lastUpdate = sdf.format(lastMod)//更新日フォーマット後

            val data:ItemData = ItemData().also {
                it.nameStamp = fileName
                it.timeStamp = lastUpdate
            }
            dataList.add(data)
        }
        dataList.sortWith(compareBy({it.nameStamp}))//ソートしてみる

        return dataList
    }
}
```
##おしまい
まだまだ理解の浅い所もありますが、こうして一つ一つ分けてみるとそこまで複雑ではないように思います。
後からアイテムの要素を追加したりするのも簡単なので結構使い勝手が良いなと感じました。