【Kotlin】RecyclerViewで無限スクロールを実装する
kotlinでRecyclerView を使って InfiniteScroll を実装するメモ
今回は単純に数字が表示されるレコードを無限スクロールさせるだけの処理
まずはRecycler Viewを使えるようにbuild.gradleに以下を追記する
projectの方ではなくappの方
dependencies {
...
implementation 'androidx.recyclerview:recyclerview:1.0.0' <-これ
}
レイアウトファイルを修正
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>
row.xml
通常レコードのレイアウトファイル
row.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:background="@color/colorPrimaryDark" android:layout_height="44dp"> <TextView android:id="@+id/textview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="8dp" android:textStyle="bold" android:textSize="17sp" android:textColor="@android:color/white" android:gravity="center_vertical" android:text="Lorem Ipsum" /> </LinearLayout>
ローディング中レコードのレイアウトファイル
ローディング中に一覧の一番下に表示するローディング表示のレコード
progressbar.xml
<?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="50dp" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="horizontal"> <ProgressBar android:id="@+id/progressbar" android:layout_width="24dp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" /> </LinearLayout> </LinearLayout>
Adapterファイルの追加
Adapterとは?
AdapterViewなどのViewとデータの橋渡しをするためのもの
RecyclerViewAdapter.kt
package com.example.android.sample.recyclerinfinitescroll import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.row.view.* import java.lang.IllegalArgumentException class RecyclerViewAdapter(var list: ArrayList<String>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { companion object{ private const val VIEW_TYPE_DATA = 0 private const val VIEW_TYPE_PROGRESS = 1 } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when(viewType){ VIEW_TYPE_DATA -> { val view = LayoutInflater.from(parent.context).inflate(R.layout.row, parent, false) DataViewHolder(view) } VIEW_TYPE_PROGRESS -> { val view = LayoutInflater.from(parent.context).inflate(R.layout.progressbar, parent, false) ProgressViewHolder(view) } else -> throw IllegalArgumentException("Different View Type") } } override fun getItemCount(): Int { return list.size } override fun getItemViewType(position: Int): Int { var viewtype = list.get(position) return when(viewtype){ "load" -> VIEW_TYPE_PROGRESS else -> VIEW_TYPE_DATA } } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { if(holder is DataViewHolder) { holder.textview.text = list.get(position) } } inner class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ var textview = itemView.textview init{ itemView.setOnClickListener { Toast.makeText(itemView.context, list.get(adapterPosition), Toast.LENGTH_LONG) .show() } } } inner class ProgressViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){ } }
MainActivityの修正
MainActivity.kt
package com.example.android.sample.recyclerinfinitescroll import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.os.Handler import android.widget.LinearLayout import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { var handler : Handler = Handler() lateinit var list: ArrayList<String> lateinit var adapter : RecyclerViewAdapter private var isLoading: Boolean = false lateinit var layoutManger: LinearLayoutManager override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) layoutManger = LinearLayoutManager(this) recyclerview.layoutManager = layoutManger list = ArrayList() load() adapter = RecyclerViewAdapter(list) recyclerview.adapter = adapter addScrollListener() } private fun addScrollListener() { recyclerview.addOnScrollListener(object: RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) if(!isLoading){ if(layoutManger.findLastCompletelyVisibleItemPosition() == list.size - 1){ loadMore() isLoading = true } } } }) } private fun loadMore() { handler.post(Runnable { list.add("load") adapter.notifyItemInserted(list.size - 1) }) handler.postDelayed(Runnable { list.removeAt(list.size - 1) var listSize = list.size adapter.notifyItemRemoved(listSize) var nextLimit = listSize + 10 for(i in listSize until nextLimit){ list.add("Item No $i") } adapter.notifyDataSetChanged() isLoading = false }, 2500) } private fun load() { for(i in 0..30){ list.add("Item No: $i") } } }
以上で簡単ではありますが、 RecyclerViewでInfiniteScroll(無限スクロール)を実装できました。 次回は API経由で取得したデータをRecyclerViewで無限スクロール方法をメモります。