はじめに
今回はReyclerViewというものを紹介していきます。
初心者の方からするとRecyclerViewとはなんぞや!となってしまいますが、簡単に説明するとリストを表示するためのViewです。
記事の対象
- Androidアプリ開発初心者
- 前回の記事を読んだ方
- Androidをこよなく愛する方
RecyclerViewとは
Androidアプリ開発の公式のリファレンス、Android Developersを見ると何やら難しいことが書いてありますね。
簡単な説明は以下のとおり
大規模なデータセット(または頻繁に変更されるデータ)に基づく要素のスクロール リストをアプリで表示する必要がある場合、このページで説明するように RecyclerView を使用する必要があります。
RecyclerViewとはスクロール可能なリストを表示してくれます。
前回のLinearLayoutはスクロールできないのでRecyclerViewを使うとよりTodoアプリっぽいものができますね!
ちょっと知っている方はScrollViewとLinearLayoutでもスクロールできるじゃん!と思うかもしれませんが、なぜRecyclerViewを使うかは最後に軽く説明しますので覗いてみてください
小難しい説明は置いておいて、まずはどんなもんか試してみましょう!
1.activity_main.xmlを書き換える
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
まずはRecyclerViewを設置します。ただこれだけで実行しても何も起きないので次行ってみましょう!
2. 1行分のレイアウトを生成する
RecyclerViewというのは対応するリストの数に合わせて動的にViewを作ってくれます。
リストの1要素に対して1行分のViewという感じです。
なのでその1行分のViewをどんなふうにしてくのかを作らなければいけないですね。
ではapp/res/layoutのの中にitem_recycler_view.xmlというファイルを作ってみましょう
app/res/layoutの部分を右クリックして、
new→Layout Resource FileをクリックしFile Nameの中に任意の名前(今回はitem_recycler_view)を入力してOKを押します。
そうすると新しいxmlファイルができましたね。
今回は1行分のレイアウトは自由に作ってみてください!
一応私のレイアウトも載せておきます。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp">
<TextView
android:id="@+id/position"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textColor="@android:color/black"
android:textSize="22sp" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="10dp"
android:textColor="@android:color/black"
android:textSize="22sp" />
</LinearLayout>
3. ViewHolderとRecyclerView.Adapter
RecylcerViewを表示するためにはこのViewHolderとRecyclerView.Adapterが必須です。
ではこいつらは一体何者なのか簡単に説明していきたいと思います。
ViewHolder
ViewHolderというのは1行分のレイアウトを保持しておくためのクラスです。
以前までfindViewByIdを使っていましたが、これは実はコストが高く、リストの要素全てに対してfindViewByIdをやっていると重たくなってしまいます。
なのでリストの要素と1行分のレイアウトを最初から紐づけておいて、画面外にレイアウトが行った後に戻ってきても同じインスタンスを使おうねというものです
ただ説明が小難しいのでわからない方はわかるまで理解しようとしなくて大丈夫です!
使ってたら勝手に覚えます笑
RecyclerView.Adapter
こいつはリストの要素と1行分のレイアウト(ViewHolder)を紐づけてくれるやつです。
4.実践
とりあえず一気に動くものを書いちゃいます
その後解説します
package com.example.helloworld
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
private lateinit var recyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val pokemonList = listOf(
"ピカチュウ",
"カイリュー",
"ヤドラン",
"ピジョン",
"コダック",
"コラッタ",
"ズバット",
"ギャロップ",
"サンダース",
"メノクラゲ",
"パウワウ",
"カラカラ",
"タマタマ",
"ガラガラ",
"フシギダネ"
)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.adapter = MyRecyclerViewAdapter(pokemonList)
recyclerView.layoutManager = LinearLayoutManager(this)
}
}
class MyRecyclerViewAdapter(val list: List<String>) : RecyclerView.Adapter<MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_recycler_view, parent, false)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.positionText.text = position.toString()
holder.titleText.text = list[position]
}
override fun getItemCount(): Int = list.size
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val positionText: TextView = itemView.findViewById(R.id.position)
val titleText: TextView = itemView.findViewById(R.id.title)
}
5.解説
まずはMyViewHolderを見ていきましょう
これは1行分のレイアウトを記述しています。
今回は番号と名前を表示したかったのでpositionTextとtitleTextを保持しています。
次にMyRecyclerViewAdapterです
まずコンストラクタにlistをもらっています。これはリストの要素と1行分のレイアウトを紐づけるためですね。
まずはonCreateViewです
ここで1行分のレイアウトを生成してくれています。
そしてonBindViewHolder
その名の通りViewHolderをBind(結ぶ)してくれます。
この関数は引数にholder(1行分のレイアウト)とposition(何行目か)というのを持っているので、リストのpositionを紐づけていきます。
最後にgetItemCountです
これはリストのアイテムが何個あるかカウントし、その分だけレイアウトを作ってくれます
次におなじみのMainActivityです
まずは表示したいリストを生成します。
KotlinのリストはlistOfだけで生成でいます。
そして以前と同様RecyclerViewのidを使ってActivity側に認識させます。
次にrecylcerViewにadapterをセットします。
最後にlayoutManagerをセットします。
これはおまじない程度だと思っていてください笑
ちなみに今回は縦一列のリストですが、横一列のRecyclerViewにする場合は
recyclerView.layoutManager=LinearLayoutManager(this, RecyclerView.HORIZONTAL, false)
というふうにしてください。
6. 補足
今回RecyclerViewに関して解説しましたが、実はListViewというものもあるのですがそちらはあまり使いません。
ListViewのアニメーションの実装難易度がかなり高いからです(コメント参照)
ScrollViewとLinearLayoutでもスクロールできるViewは作れますが、リストの数だけaddViewしなければならず、こちらもコストを考えると実践的ではありませんね。
リストの数が少ないうちはScrollView&LinearLayoutで全く問題ないですが、リストの数が増えれば増えるほど重たくなり最悪のアプリになってしまいます。それは避けたいのでリストを表示するときはなるべくRecyclerViewを使いたいですね!
7. まとめ
今回はRecyclerViewについて解説していきました。
Todoアプリが完成するまで時間の問題になってきましたね!
あと3〜5記事くらいでTodoアプリが完成すると思いますが、ここからが正念場ですので気合入れていきましょう!
わからないこと、つまづいていることなどございましたらコメント欄かTwitterのDMに送っていただければ解決するまでお付き合いいたしますのでどうぞご気軽にご連絡ください!