RecyclerView의 구성요소
1. Adapter (필수) :
항목을 구성하는 역할
데이터와 RecyclerView 사이의 연결을 위한 객체
2. ViewHolder (필수) :
항목에 필요한 뷰 객체를 가지는 역할
RecyclerView의 개념을 적용하기위해선 스크롤 해서 위로 올라간
View를 재활용하기 위해서 이 View를 기억하고 있어야 한다.
ViewHolder가 그 역할을 함.
3. LayoutManager (필수) : 항목을 배치하는 역할
4. ItemDecoration (옵션) : 항목을 꾸미기 위한 역할
5. ItemAnimation (옵션)
RecyclerView를 만들어주기 위해 메인화면 레이아웃에서 위젯을 RecyclerView로 변경한다.
<?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"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recycler"/>
</LinearLayout>
그 다음에 RecyclerView에서 나타낼 item이라는 layout 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="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/iconItem"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:scaleType="centerCrop"
android:padding="@dimen/icon_padding"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:src="@drawable/ex1"
/>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2">
<TextView
android:id="@+id/textItem1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="@dimen/list_item_text_size1"
android:padding="@dimen/list_item_padding"
android:hint="Name"
/>
<TextView
android:id="@+id/textItem2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="@dimen/list_item_text_size2"
android:padding="@dimen/list_item_padding"
android:hint="Age"
/>
</LinearLayout>
</LinearLayout>
항목 뷰에 표시할 데이터를 정의한 MyItem 클래스 정의
data class MyItem(val aIcon:Int, val aName:String, val aAge:String) {
}
* 데이터 클래스는 데이터를 다루는데 최적화된 클래스로
equals(), hashCode(), toString(), copy(), componentN()
5가지 유용한 함수들을 내부적으로 자동으로 생성해준다.
앞서 정의한 MyItem 타입의 객체들을 MutableList로 관리하는 MyAdapter 클래스를 RecyclerView.Adapter에 파생하여 정의
package com.example.recyclerview
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.recyclerview.databinding.ActivityMainBinding
import com.example.recyclerview.databinding.ItemBinding
class MyAdapter(val mItems: MutableList<MyItem>) : RecyclerView.Adapter<MyAdapter.Holder>() {
interface ItemClick {
fun onClick(view : View, position : Int)
}
var itemClick : ItemClick? = null
// 항목의 뷰를 가지는 ViewHolder를 준비하기 위해 자동 호출
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val binding = ItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Holder(binding)
}
// ViewHolder의 뷰에 데이터를 출력하기 위해서 자동 호출
override fun onBindViewHolder(holder: Holder, position: Int) {
holder.itemView.setOnClickListener { //클릭이벤트추가부분
itemClick?.onClick(it, position)
}
holder.iconImageView.setImageResource(mItems[position].aIcon)
holder.name.text = mItems[position].aName
holder.age.text = mItems[position].aAge
}
// 항목 id를 항목의 위치로 간주함
override fun getItemId(position: Int): Long {
return position.toLong()
}
// MyAdapter 클래스가 관리하는 항목의 개수를 판단하기 위해 자동 호출
override fun getItemCount(): Int {
return mItems.size
}
// ViewHolder는 RecyclerView.ViewHolder를 상속받아 작성
inner class Holder(val binding: ItemBinding) : RecyclerView.ViewHolder(binding.root) {
val iconImageView = binding.iconItem
val name = binding.textItem1
val age = binding.textItem2
}
}
여기서 inner class란.
자바에서는 A클래스 안에 B클래스를 정의하면 B클래스는 자동으로 A클래스의 내부 클래스가 되어서
A클래스 안의 객체를 참조할 수 있다. 코틀린에서는 반대이고, 기본적으로 중첩 클래스가 된다.
내부 클래스로 만들기 위해서는 inner 키워드를 사용하여 클래스를 선언해야 한다.
package com.example.recyclerview
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.recyclerview.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding // viewBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 데이터 원본 준비
val dataList = mutableListOf<MyItem>()
dataList.add(MyItem(R.drawable.ex1, "Bella", "1"))
dataList.add(MyItem(R.drawable.ex2, "Charlie", "2"))
dataList.add(MyItem(R.drawable.ex3, "Daisy", "1.5"))
dataList.add(MyItem(R.drawable.ex4, "Duke", "1"))
dataList.add(MyItem(R.drawable.ex5, "Max", "2"))
dataList.add(MyItem(R.drawable.ex6, "Happy", "4"))
dataList.add(MyItem(R.drawable.ex7, "Luna", "3"))
dataList.add(MyItem(R.drawable.ex8, "Bob", "2"))
dataList.add(MyItem(R.drawable.ex1, "Bob", "2"))
dataList.add(MyItem(R.drawable.ex2, "Bob", "2"))
dataList.add(MyItem(R.drawable.ex3, "Bob", "2"))
binding.recycler.adapter = MyAdapter(dataList)
// RecyclerView에 Adapter와 LayoutManager를 등록시켜 화면에 출력
val adapter = MyAdapter(dataList)
binding.recycler.adapter = adapter
binding.recycler.layoutManager = LinearLayoutManager(this)
}
}
이제 실행을 하면
짜잔
어렵지만,, RecyclerView가 현업에서 비율이 높게 쓰인다는데 그만큼 열심히 공부해야한다는거겠지?
그리고 오늘 팁을 얻었는데 여기서 LinearLayout을 중첩시켜놨는데 그럴 필요 없이 constraintlayout으로 더 깔끔하게 만들어주는게 좋다고 한다. 오늘 더 친해진 '친구'가 알려줬다(chatgpt 아님). 친구 생김 ㅎㅎ
음 여기에 뭔가 댓글 달았던 기억이 나는데 사라져있는거 같아요
오늘 너무 감사했습니다!!