View

이중 RecyclerView

제롱구리 2024. 2. 16. 20:04
728x90

RecyclerView 내부 아이템에 RecyelerView가 필요할 때?


개인 프로젝트인 로스트아크 앱을 개발하는 도중 RecyclerView안에 있는 Item 값안에 RecyclerView가 필요한 경우가 생기게 되었다.

위 사진 처럼 모험 섬이라는 Item안에 각각의 보상 아이템 이미지가 들어가는 경우다.

즉 모험 섬이 부모 RecyclerView의 Item이고 각각의 보상 아이템 이미지가 자식 RecyclerView의 Item이 된다.

어떻게 해야될까?

해당 문제가 생겼을 때 처음에 난 매우 간단히 생각했다.

바로 해당 부모 RecyclerView Item안에 RecyclerView를 선언 해서 만든는 법이다.
여기까지는 무척 좋았다. 간단하지만 생각 못했던 문제를 만나기 전까지는....

일단 나는 각각의 Item layout를 작성해주었다.


[item_andventure_island.xml] 모험 섬 Item

아래 코드를 보면 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="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/shape_outbalck_inwhite_thin_round_bg">

    <TextView
        android:id="@+id/tv_island_name_item"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="섬 이름"
        android:textColor="@color/white"
        android:textSize="20dp"
        android:background="@drawable/tv_background_gradient_center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/iv_island_image_item"
        android:layout_width="200dp"
        android:layout_height="150dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_reward_tag"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:gravity="left"
        android:text="기대 모험 보상"
        android:textColor="@color/clr_D6D6D6"
        android:textSize="15dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/iv_island_image_item" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_reward_item"
        android:layout_width="200dp"
        android:layout_height="100dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_reward_tag"/>


</androidx.constraintlayout.widget.ConstraintLayout>

[item_reward_image.xml] 보상 아이템 이지미 Item

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_marginTop="5dp"
    android:layout_marginStart="5dp">

    <ImageView
        android:id="@+id/iv_reward_image"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_width="30dp"
        android:layout_height="30dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>    

[AdventureIslandAdapter] 모험 섬 adapter


class AdventureIslandAdapter(
//    private val matchPlayerRecyclerListener: MatchPlayerRecyclerListener,
    private val contentsCalendarResultList: ArrayList<ContentsCalendarResult>,
) : RecyclerView.Adapter<AdventureIslandViewHolder>(){

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AdventureIslandViewHolder {
        val itemBinding =
            ItemAdventureIslandBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return AdventureIslandViewHolder(itemBinding)
    }

    override fun onBindViewHolder(holder: AdventureIslandViewHolder, position: Int) {
        holder.bind(contentsCalendarResultList[position])
    }

    override fun getItemCount(): Int {
        return contentsCalendarResultList.size
    }
}

[AdventureIslandViewHolder] 모험 섬 ViewHolder

class AdventureIslandViewHolder(
    private val binding: ItemAdventureIslandBinding,
) : RecyclerView.ViewHolder(binding.root) {

    fun bind(contentsCalendarResult: ContentsCalendarResult) {

        binding.tvIslandNameItem.text = contentsCalendarResult.contentsName
        Glide.with(itemView.context)
            .load(contentsCalendarResult.contentslcon)
            .error(R.drawable.painter1)
            .placeholder(R.drawable.painter2)
            .fitCenter()
//            .override(1200,  700)
            .into(binding.ivIslandImageItem)
        binding.rvRewardItem.apply {
            //여기에 어떻게 보상 아이템 이미지의 adapter를 연결할지....
            //context가 필요하다. Manager를 하기 위해서는.....
            layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL,false)
            adapter = RewardItemAdapter(context,contentsCalendarResult.rewardItems)
        }
    }
}

문제 발생 및 해결

간단히 ViewHolder를 작성 중 문제가 발생하고 말았다.
보통 RecyclerView의 adapter를 연결할 때 LinearLayoutManager를 사용하는데 여기에 파라미터 값으로 해당 Activity의 context가 필요하다. 그렇지만 ViewHolder에는 따로 context가 있지 않기 때문에 어떻게 해야될까라는 고민을 할 수 있다.
나도 처음 안드로이드를 개발할 때는 잘이해하지 못해서 여기서 막혔다. 하지만 지금 생각해보면 의외로 간단한 방법이 있다.
바로 Activity에서 context를 인자로 받아서 그냥 adapter와 ViewHolder까지 끌고 오는 방법이다.


[AdventureIslandAdapter] 모험 섬 adapter 해결 후


class AdventureIslandAdapter(
    private val context: Context,
//    private val matchPlayerRecyclerListener: MatchPlayerRecyclerListener,
    private val contentsCalendarResultList: ArrayList<ContentsCalendarResult>,
) : RecyclerView.Adapter<AdventureIslandViewHolder>(){

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AdventureIslandViewHolder {
        val itemBinding =
            ItemAdventureIslandBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return AdventureIslandViewHolder(itemBinding)
    }

    override fun onBindViewHolder(holder: AdventureIslandViewHolder, position: Int) {
        holder.bind(context, contentsCalendarResultList[position])
    }

    override fun getItemCount(): Int {
        return contentsCalendarResultList.size
    }
}

[AdventureIslandViewHolder] 모험 섬 ViewHolder 해결 후

class AdventureIslandViewHolder(
    private val binding: ItemAdventureIslandBinding,
) : RecyclerView.ViewHolder(binding.root) {

    fun bind(context: Context,  contentsCalendarResult: ContentsCalendarResult) {

        binding.tvIslandNameItem.text = contentsCalendarResult.contentsName
        Glide.with(itemView.context)
            .load(contentsCalendarResult.contentslcon)
            .error(R.drawable.painter1)
            .placeholder(R.drawable.painter2)
            .fitCenter()
//            .override(1200,  700)
            .into(binding.ivIslandImageItem)
        binding.rvRewardItem.apply {
            layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL,false)
            adapter = RewardItemAdapter(context,contentsCalendarResult.rewardItems)
        }

    }
}

바로 이렇게 context를 가져오면된다. 이렇게 하면 이중 RecyclerView의 문제를 해결할 수 있다. ㅎㅅㅎ

현재..Rxjava 늪에 빠졌다..아...에휴....3일째....

'TIL' 카테고리의 다른 글

앱 아이콘 설정하기  (0) 2024.02.23
Rxjava 적용(4일째 고민...)  (1) 2024.02.19
변수와 상수  (2) 2024.02.14
자료형이란?  (1) 2024.02.13
Convention란?  (0) 2024.02.13
Share Link
reply
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30