외로운 Nova의 작업실

안드로이드 앱 프로그래밍 - 14(제트팩 라이브러리 - 리사이클러뷰) 본문

Programming/Kotlin - Android

안드로이드 앱 프로그래밍 - 14(제트팩 라이브러리 - 리사이클러뷰)

Nova_ 2023. 1. 19. 16:49

- 리사이클러 뷰

일반적으로 앱을 사용하다 보면 여러가지 항목을 나열하는 목록 화면이 많다는 것을 알 수 있습니다. 리사이클러 뷰는 이러한 목록 화면을 만들때 사용합니다. 아래와 같은 상황을 말합니다.

리사이클러 뷰는 뷰 홀더라는 틀을 만들고 그 틀에 어댑터가 값을 넣어주고 이후 레이아웃매니저가 여러개 배치해주는 순서로 진행됩니다.

하나씩 만들어보겠습니다.

 

- 리사이클러 뷰 선언

먼저 리사이클러를 사용하겠다고 그래들 파일에 선언해줘야합니다.

implementation 'androidx.recyclerview:recyclerview-selection:1.1.0'

 

- 리사이클러를 메인 xml에 등록

메인 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:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recyclerView"/>
</androidx.constraintlayout.widget.ConstraintLayout>

 

- 리사이클러의 틀을 xml로 만들기

이제 리사이클러의 틀을 xml로 만들어줍니다. 이번 경우에는 텍스트가 하나 들어가는 항목으로 만들겠습니다. 이름은 item_main.xml입니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="16dp">
    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textStyle="bold"
        android:id="@+id/item_data"
        android:textSize="16dp"/>
</LinearLayout>

 

- 뷰 홀더 준비

이제 메인 액티비티상에서 item_main.xml을 받아오는 홀더를 준비합니다.

class MyViewHolder(val binding: ItemMainBinding): RecyclerView.ViewHolder(binding.root)

 

- 어댑터 준비

이제 홀더에 값을 넣어주는 어댑터를 만들어줍니다.

class MyAdaptor(private val datas: MutableList<String>):
        RecyclerView.Adapter<RecyclerView.ViewHolder>(){
    override fun getItemCount(): Int {
        TODO("Not yet implemented")
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        TODO("Not yet implemented")
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        TODO("Not yet implemented")
    }
        }

각 함수는 아래와 같습니다.

  • getItemCount() : 항목의 개수를 판단하려고 자동으로 호출됩니다.
  • onCreateViewHolder() : 항목의 뷰를 가지는 뷰 홀더를 준비하려고 자동으로 호출됩니다.
  • onBindingViewHolder() : 뷰홀더의 뷰에 데이터를 출력하려고 자동으로 호출됩니다.

<getItemCount() 작성>

getItemCount()함수는 자동으로 호출되어 항목의 개수를 리턴합니다. 이때 0을 반환하면 화면에는 아무것도 보이지않습니다. 따라서 개수를 return 해줘야합니다.

override fun getItemCount(): Int {
        return datas.stize
    }

나중에 datas를 선언할 예정입니다.

 

<getCreateViewHolder() 함수 작성>

getCreateViewHolder() 함수는 항목을 구성할때 이용할 뷰 홀더 객체(틀)을 받아옵니다. 즉 Binding 객체를 이용해 xml파일을 아까만든 MyViewHolder에 담아습니다.

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return MyViewHolder(ItemMainBinding.inflate(LayoutInflater.from(parent.context), parent, false))
    }

 

<onBindingViewHolder() 작성>

onBindingViewHolder() 함수는 뷰홀더(틀)에 이제 데이터를 작성합니다. 이때 뷰홀더 객체는 onCreateViewHolder()함수에서 반환한 객체를 받아옵니다.

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        Log.d("log", "on bindViewHolder : $position")
        val binding = (holder as MyViewHolder).binding
        //뷰에 데이터 출력
        binding.itemData.text = datas[position]
        //뷰에 이벤트 추가
        binding.itemRoot.setOnClickListner{
            Log.d("log", "item root click : $position")
        }
    }

빨간색이 뜨더라도 괜찮습니다. 어댑터를 만들지 않아서 그렇습니다. 한번 만들어보겠습니다

 

- 메인액티비티상에서 레이아웃매니저 사용하기

이제 실제 메인액티비티에서 어댑터를 계속 사용하여 출력해주는 레이아웃매니저를 사용합니다.

binding.recyclerView.layoutManager = LinearLayoutManager(this)
        binding.recyclerView.adapter = MyAdaptor(datas)
        binding.recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))

 

- 실제 완성 코드

 

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val datas = mutableListOf<String>()
        for(i in 1..10){
            datas.add("Item $i")
        }

        class MyViewHolder(val binding: ItemMainBinding): RecyclerView.ViewHolder(binding.root) //뷰 홀더

        class MyAdaptor(private val datas: MutableList<String>):
            RecyclerView.Adapter<RecyclerView.ViewHolder>(){
            override fun getItemCount(): Int {
                return datas.size
            }

            override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
                return MyViewHolder(ItemMainBinding.inflate(LayoutInflater.from(parent.context), parent, false))
            }

            override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
                Log.d("log", "on bindViewHolder : $position")
                val binding = (holder as MyViewHolder).binding
                //뷰에 데이터 출력
                binding.itemData.text = datas[position]
            }
        }
        
        binding.recyclerView.layoutManager = LinearLayoutManager(this)
        binding.recyclerView.adapter = MyAdaptor(datas)
        binding.recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))

    }
}

Comments