RecyclerView란 아래와 같이 한 화면에 동일한 형식의 아이템(뷰)을 여러개 출력하고, 스크롤을 통해 아이템들을 확인할 수 있도록 구성하는 뷰이다.
첫 번째로 동일한 형식의 아이템뷰 파일을 생성한다. layout 리소스에 post_detail.xml 파일을 생성한다.
위와 같이 화면이 구성되도록 post_detail.xml 파일을 작성한다.
//Adapter : 데이터와 아이템에 관한 View를 생성.
inner class PostAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private lateinit var postDetailBinding: PostDetailBinding
private var store: FirebaseFirestore = FirebaseFirestore.getInstance()
private var contentsList = arrayListOf<ContentDTO>()
//DB에서 게시글 데이터 가져오기
init {
store.collection("posts")
.orderBy("timestamp", Query.Direction.DESCENDING)
.addSnapshotListener { posts, e->
if (e!=null) {
println(e)
Toast.makeText(activity, R.string.upload_fail, Toast.LENGTH_SHORT).show()
} else {
contentsList.clear()
for (post in posts!!.documents) {
var content = post.toObject(ContentDTO::class.java)
contentsList.add(content!!)
}
}
notifyDataSetChanged()
}
}
//post_detail.xml을 아이템뷰 생성
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
var inflater: LayoutInflater = parent.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
postDetailBinding = PostDetailBinding.inflate(inflater, parent, false)
return PostHolder(postDetailBinding.root)
}
//아이템뷰 화면에 입력돼야 할 데이터 추가.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
postDetailBinding.usernameTextView.text = contentsList.get(position)!!.userEmail
Glide.with(holder.itemView).load(contentsList.get(position).imageUrl).into(postDetailBinding.postPhotoIV)
postDetailBinding.favoriteCountTextView.text = "좋아요 ${contentsList.get(position)!!.favoriteCount}개"
postDetailBinding.postTextView.text = contentsList.get(position).exaplain
}
//총 몇 개의 아이템이 추가되어야 하는지 확인.
override fun getItemCount(): Int {
return contentsList.size
}
}
Home 화면에 적용할 아이템뷰(post_detail.xml)를 생성하는 PostAdapter 클래스를 생성한다. 해당 클래스는 RecyclerView.Adapter
클래스를 상속받고, onCreateViewHolder()
, onBindViewHolder()
, getItemCount()
메서드를 오버라이딩한다.
첫 번째로 화면에 적용할 게시글 데이터가 필요하기 때문에 생성자로 Firebase Firestore에서 데이터를 읽어오고 ContentDTO arrayList를 생성한다.
onCreateViewHolder()
메서드에서는 사용하고자 하는 아이템뷰를 생성한다. 여기서는 post_datail.xml 파일을 아이템뷰로 생성한다.
onBindViewHolder()
메서드는 아이템뷰에 가져온 데이터를 적용하는(바인딩) 메서드이다. contentDTO에서 사용자 이메일, 게시글 이미지, 게시글, 좋아요 수 데이터를 이용해 화면에 바인딩한다.
getItemCount()
메서드는 필요한 아이템의 수를 리턴하면 된다. 이곳에선 게시글 데이터 수만큼 아이템을 생성해야 하므로 ContentDTO arrayList의 사이즈를 리턴한다.
//뷰를 보관하는 Holder 객체.
//item 뷰들을 재활용하기 위해 각 요소를 저장해두고 사용.
//아이템 생성시 뷰 바인딩은 한 번만 하고, 바인딩 된 객체를 가져다 사용해 성능이 효율적.
inner class PostHolder(root: View) : RecyclerView.ViewHolder(root)
viewHolder는 adapter 클래스에서 생성한 아이템뷰를 보관하는 클래스이다. 아이템 뷰 생성과 바인딩은 딱 한 번 생성되고, 필요할 때마다 viewHolder에 보관된 아이템뷰를 가져다 사용(재활용)한다.
//아이템 간 수직(위아래) 간격 설정
inner class VerticalItemDecorator(var divHeight: Int):RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.top = divHeight
outRect.bottom = divHeight
}
}
ItemDecoration을 사용하면 아이템 간의 간격을 설정할 수 있다. 해당 화면에서는 아이템 간의 수직 간격(위아래)을 띄우기 위해 사용했다.
HomeFragement.kt에 지금까지 만든 리사이클러뷰를 적용하기 위해 layout 파일로 이동하여 RecyclerView를 추가한다.
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/postsRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
class HomeFragment: Fragment() {
private lateinit var mBinding: FragmentHomeBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mBinding = FragmentHomeBinding.inflate(inflater, container, false)
mBinding.postsRecyclerView.adapter = PostAdapter()
//layoutManager : 아이템의 배치를 담당.
//LinearLayoutManager : 가로/세로
//GirdLayoutManager : 그리드 형식
//StaggeredGirdLayoutManager : 지그재그형의 그리드 형식
mBinding.postsRecyclerView.layoutManager = LinearLayoutManager(activity)
mBinding.postsRecyclerView.addItemDecoration(VerticalItemDecorator(30))
return mBinding.root
}
리사이클러뷰에 지금 만든 어댑터 클래스를 생성하고, layoutManager를 이용해 아이템의 배치를 어떻게 할 것인지 설정한다. 그리고 생성한 ItemDecoration 클래스를 사용해 아이템 간 간격을 설정한다.
[출처] 개발일지-[Android/Kotlin] RecyclerView 만들기
[출처] Bbaktaeho-[Android] RecyclerView (리사이클러뷰, 뷰홀더, ViewHolder)