[Android/Kotlin] RecyclerView Last Item Check - 리스트 마지막 항목

Notepad96

·

2022. 8. 24. 10:53

300x250

 

 

1. 요약

 

결과

 

이번 글에서는 RecyclerView를 사용하여 만들어진 리스트에서 마지막 항목이 되었을 때를 체크하여 동작을 정의하는 방법에 관하여 기술한다.

 

 

 

 

 

 

 

2. 레이아웃

 

2-1. activity_main.xml

메인 레이아웃으로서 RecyclerView 1개로 구성하였다.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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/recyclerView01"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

 


 

2-2. item_list.xml

RecyclerView 리스트에서 보여줄 각 항목(Item)의 대한 레이아웃을 정의한 파일로서 TextView 2개로 구성하였다.

 

<?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="10dp">

    <TextView
        android:id="@+id/mainText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Main"
        android:textSize="20sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/subText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Sub"
        android:gravity="right"
        android:textSize="18sp" />

</LinearLayout>

 

 

 

 

3. 코드 및 설명

 

3-1. RecyclerAdapter.kt

RecyclerView의 Adapter로서 각 항목의 Text는 간단하게 항목의 Position 값에 따라 나타내었다.

 

 

package com.notepad96.recyclerviewlastitem

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.notepad96.recyclerviewlastitem.databinding.ItemListBinding

class RecyclerAdapter: RecyclerView.Adapter<RecyclerAdapter.MyView>() {

    inner class MyView(private val binding: ItemListBinding): RecyclerView.ViewHolder(binding.root) {
        fun bind(pos: Int) {
            binding.mainText.text = "$pos"
            binding.subText.text = "${pos * pos}"
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyView {
        val view = ItemListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return MyView(view)
    }

    override fun onBindViewHolder(holder: MyView, position: Int) {
        holder.bind(position)
    }

    override fun getItemCount(): Int {
        return 40
    }
}

 


 

3-2. MainActivity.kt

마지막 항목을 체크하기 위해서는 RecyclerView에 addOnScrollListener를 통하여  RecyclerView.OnScrollListener 리스너를 재정의 해주어야 한다.

 

recyclerView의 canScrollVertically은 수직 리스트에 사용하여 1이면 하단을, -1이면 상단을 체크한다.

(수평 방향 리스트일 경우 canScrollHorizontally를 사용 가능하며 오른쪽이 1, 왼쪽이 -1을 나타낸다.)

 

 

마지막 항목임을 확인하였을 경우 Count 값이 1씩 증가하는 Toast 메시지를 발생하도록 하였다.

 

package com.notepad96.recyclerviewlastitem

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.notepad96.recyclerviewlastitem.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private val binding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        binding.recyclerView01.apply {
            adapter = RecyclerAdapter()
            layoutManager = LinearLayoutManager(context)
        }

        var count = 0
        binding.recyclerView01.addOnScrollListener(object: RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                if(!binding.recyclerView01.canScrollVertically(1)
                    && newState == RecyclerView.SCROLL_STATE_IDLE) {
                    Toast.makeText(applicationContext, "Last Item (${count++})", Toast.LENGTH_SHORT).show()
                }
            }
        })
    }
}

 

이렇게 설정해주면 마지막 Item일 경우 충분히 감지되지만, 가끔 연속으로 인식되어 중복으로 발생하게 되는 문제가 발생한다.

 

따라서 이를 방지하기 위해서  newState(새 상태)가 SCROLL_STATE_IDLE인지를 추가적으로 체크해줌으로써 중복 발생을 방지할 수 있다.

 

SCROLL_STATE_IDLE은 현재 RecyclerView가 스크롤되지 않는 상태임을 나타내며 이외의 SCROLL STATE에 대한 것은 아래 글을 참조하면 된다.

 

 

 

 

4. 전체 파일

 

 

GitHub - Notepad96/BlogExample02

Contribute to Notepad96/BlogExample02 development by creating an account on GitHub.

github.com

 

300x250