RecyclerViewをはじめて見た人
駅のホーム降りて、エスカレーターを降りるたとき、ふとRecyclerViewを実装したくなりました。
偶然にもAndroid Studioもインストールしてあったため、やってみることにしました。
どのサイトを見てもアホな私にはわかりにくかったため、これ見れば誰でもできる(少なくとも私は)というようなまとめをかいてみます。用語もわからないので感覚です。
間違いがあったらお教えください。
- やりたいこと
1.Gmailみたいなリストを作る
2.スワイプして削除
3.ぐりぐり動かして並び替え
- まず、作成したxmlビュー一覧です。
名前 | 役割 |
---|---|
one_item | 1行分のデータのレイアウトを決める |
activity_main | ここにRecyclerViewを入れる |
- まず、実装したクラスをすべてまとめました。MainActivityは除いてます。
クラス名(引数型) | スーパークラス | 役割 |
---|---|---|
OneItem | なし | 1行分のデータの中身を決める |
ViewHolder(View) | RecyclerView.ViewHolder | xmlで決めた1行分のデータViewを受け取って、ついでにその中の情報をもらう |
RecyclerViewAdapter(MutableList) | RecyclerView.Adapter | 上で1行1行ちまちまつくってたのをまとめて、RecyclerView本体にセット! |
クラスごとのコードです。必要最小限の実装にしてあるので、これをサンプルにして他の機能を追加してください。自分用のメモでもあるので、省略せず全部書きます。
1.one_item.xml・・・・・・textViewだけ実装しておきます。
<?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:orientation="vertical" android:layout_width="match_parent" android:layout_height="120dp"> <TextView android:layout_width="100dp" android:layout_height="wrap_content" android:id="@+id/textview" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginTop="8dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"/> </androidx.constraintlayout.widget.ConstraintLayout>
2. activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:showIn="@layout/activity_main" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="0.1" android:id="@+id/recyclerView"/> </androidx.constraintlayout.widget.ConstraintLayout>
3.ViewHolderクラス
package com.(プロジェクト名).recyclertest import android.view.View import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.one_item.view.* class ViewHolder(itemView : View): RecyclerView.ViewHolder(itemView){ var text : TextView? = null init{ //コンストラクタ text = itemView.textview } }
4. OneItemクラス
package com.(プロジェクト名).recyclertest class OneItem() { var text:String = "" }
5.CustomRecyclerViewAdapterクラス
勝手にオーバーライドしてきたメソッドたちです。こういうのが必要なんでしょうね。
・ミュータブルリストを受け取ります。MainActivityで作成しているのですが、ここに1つ1つの行のデータが入っているので、責任重大です。
メソッド名 | 役割 |
---|---|
onCreateViewHolder | ViewHolderを作成します。 |
getItemCount | リストの中身の数を返します。結局使わなかったけど、全何件!とかを出すときには使えると思います。 |
onBindViewHolder | リストの要素1つ1つとViewHolderを結び付けます。 |
package com.(プロジェクト名).recyclertest import android.content.Intent import android.graphics.Color import android.text.format.DateFormat import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView class CustomRecyclerViewAdapter(list : MutableList<OneItem>):RecyclerView.Adapter<ViewHolder>() { private val list:MutableList<OneItem> = list override fun onCreateViewHolder(parent: ViewGroup, position: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.one_item,parent,false) val viewholder = ViewHolder(view) //ViewHolderを生成、それを返す return viewholder } override fun getItemCount(): Int { //サイズ return list.size } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = list[position] holder.text?.text = item.text } }
6.MainActivityクラス
package com.(プロジェクト名).recyclertest import android.media.MediaRouter import android.os.Bundle import com.google.android.material.snackbar.Snackbar import androidx.appcompat.app.AppCompatActivity; import android.view.Menu import android.view.MenuItem import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { private lateinit var adapter:CustomRecyclerViewAdapter private lateinit var layoutManager: RecyclerView.LayoutManager private lateinit var itemDecoration: DividerItemDecoration override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } override fun onStart() { super.onStart() itemDecoration = DividerItemDecoration(this,DividerItemDecoration.VERTICAL) layoutManager = LinearLayoutManager(this) recyclerView.layoutManager=layoutManager adapter = CustomRecyclerViewAdapter(makeRecyclerData()) recyclerView.adapter = this.adapter recyclerView.addItemDecoration(itemDecoration) val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.LEFT) { override fun onMove( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder ): Boolean { val from = viewHolder.adapterPosition?:0 val to = target.adapterPosition?:0 recyclerView.adapter?.notifyItemMoved(from,to) return true } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { viewHolder.let{ recyclerView.adapter?.notifyItemRemoved(viewHolder.adapterPosition) } }}) itemTouchHelper.attachToRecyclerView(recyclerView) } fun makeRecyclerData():MutableList<OneItem>{ var recyclerData :MutableList<OneItem> = mutableListOf() for(i in 0..50){ var oneitem:OneItem= OneItem() oneitem.text="アイテム"+i.toString() recyclerData.add(oneitem) } return recyclerData } }
注意点1.RecyclerViewには区切り線をxmlで実装する方法がないようです。
そのため、MainActivityで
itemDecoration = DividerItemDecoration(this,DividerItemDecoration.VERTICAL)
注意点2.スワイプして削除、ドラッグして入れ替えしているのはこの部分。
val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.LEFT) { override fun onMove( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder ): Boolean { val from = viewHolder.adapterPosition?:0 val to = target.adapterPosition?:0 recyclerView.adapter?.notifyItemMoved(from,to) return true } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { viewHolder.let{ recyclerView.adapter?.notifyItemRemoved(viewHolder.adapterPosition) } }}) itemTouchHelper.attachToRecyclerView(recyclerView) }
その他解説は少しずつ追加していきたいと思います。
醜いコードだとは思いますが・・・その辺ご指摘お願いいたします。