관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[안드로이드] 안드로이드 이중 어댑터(이중 리사이클러뷰) 구현 메모 (feat. 데이터바인딩) 본문

안드로이드/코틀린 & 아키텍처 & Recent

[안드로이드] 안드로이드 이중 어댑터(이중 리사이클러뷰) 구현 메모 (feat. 데이터바인딩)

막무가내막내 2020. 8. 31. 20:09
728x90

 

[2021-04-14 업데이트]

 

안녕하세요 ㅎㅎ

이중 어댑터 (이중 리사이클러뷰)를 데이터바인딩과 엮어서 구현해본거는 처음이라 기록용!!! 으로 남깁니다. (바빠서 따로 설명은 달지 않겠습니다 .ㅠㅠ)

 

디자이너분이 밑과같이 하나의 아이템리스트에 해쉬태그가 한줄로 좌우 스크롤을 할 수 있게 해달라고 하셨습니다.

그래서 큰아이템리스트(사진과 글)과 그안에 리사이클러뷰를 horiziontal 로 하나 더 두어 이중 어댑터(리사이클러뷰) 구조로 구현을 했습니다.  간단히 설명드리면 처음 어댑터에서 VIewHodler 쪽에서 어댑터를 생성해 해쉬태그어댑터(두번쨰어댑터)에 세팅을 해주는 형식으로 구현했습니다.

 

 

먼저 큰 아이템 xml 과 어댑터입니다.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:bind="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="item"
            type="com.mtjin.nomoneytrip.data.home.Product" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/margin_12dp">

        <androidx.cardview.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:cardCornerRadius="@dimen/radius_16dp"
            app:cardElevation="0dp"
            app:layout_constraintTop_toTopOf="parent">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/bg_item_product_radius_16dp">

                <androidx.appcompat.widget.AppCompatImageView
                    android:id="@+id/iv_image"
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/height_180dp"
                    android:scaleType="fitXY"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    bind:urlImage="@{item.image}"
                    tools:src="@drawable/busan" />

                <androidx.appcompat.widget.AppCompatImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/margin_12dp"
                    android:layout_marginEnd="@dimen/margin_12dp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:srcCompat="@drawable/ic_save_white_off" />

                <androidx.constraintlayout.widget.ConstraintLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingBottom="@dimen/padding_16dp"
                    app:layout_constraintTop_toBottomOf="@id/iv_image">

                    <androidx.appcompat.widget.AppCompatTextView
                        android:id="@+id/tv_content"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="@dimen/margin_16dp"
                        android:layout_marginTop="@dimen/margin_16dp"
                        android:layout_marginEnd="@dimen/margin_16dp"
                        android:ellipsize="end"
                        android:maxLines="2"
                        android:text="@{item.content}"
                        android:textColor="@color/colorBlack2D2D"
                        android:textSize="@dimen/text_size_14sp"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent"
                        tools:text="무전숙박 상품 타이틀입니다.\n 재미있게
두줄까지 작성 가능합니다." />

                    <androidx.recyclerview.widget.RecyclerView
                        android:id="@+id/rv_hash_tags"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="@dimen/margin_24dp"
                        android:orientation="horizontal"
                        android:paddingStart="@dimen/padding_16dp"
                        android:paddingEnd="0dp"
                        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@id/tv_content"
                        bind:setItems="@{item.hashTagList}"
                        tools:listitem="@layout/item_product_hash_tag" />
                </androidx.constraintlayout.widget.ConstraintLayout>
            </androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.cardview.widget.CardView>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
package com.mtjin.nomoneytrip.views.home

import android.content.Context
import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.mtjin.nomoneytrip.R
import com.mtjin.nomoneytrip.data.home.Product
import com.mtjin.nomoneytrip.databinding.ItemProductBinding
import com.mtjin.nomoneytrip.utils.getMyDrawable
import com.mtjin.nomoneytrip.utils.uuid

class HomeProductAdapter(
    private val context: Context,
    private val itemClick: (Product) -> Unit,
    private val favoriteClick: (Product) -> Unit
) :
    RecyclerView.Adapter<HomeProductAdapter.ViewHolder>() {
    private val items: ArrayList<Product> = ArrayList()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding: ItemProductBinding = DataBindingUtil.inflate(
            LayoutInflater.from(parent.context),
            R.layout.item_product,
            parent,
            false
        )
        val viewHolder = ViewHolder(binding)
        binding.root.setOnClickListener {
            itemClick(items[viewHolder.adapterPosition])
        }
        binding.ivFavorite.setOnClickListener {
            items[viewHolder.adapterPosition].let {
                if (it.favoriteList.contains(uuid)) {
                    val img: Drawable? = context.getMyDrawable(R.drawable.ic_save_white_off)
                    binding.ivFavorite.setImageDrawable(img)
                    items[viewHolder.adapterPosition].favoriteList.remove(uuid)
                } else {
                    val img: Drawable? = context.getMyDrawable(R.drawable.ic_save_on)
                    items[viewHolder.adapterPosition].favoriteList.add(uuid)
                    binding.ivFavorite.setImageDrawable(img)
                }
                favoriteClick(items[viewHolder.adapterPosition])
            }
        }
        return viewHolder
    }

    override fun getItemCount(): Int = items.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        items[position].let {
            holder.bind(it)
        }
    }

    inner class ViewHolder(private val binding: ItemProductBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(item: Product) {
            val adapter = ProductHashTagAdapter()
            binding.rvHashTags.adapter = adapter
            binding.item = item
            if (item.favoriteList.contains(uuid)) {
                val img: Drawable? = context.getMyDrawable(R.drawable.ic_save_on)
                binding.ivFavorite.setImageDrawable(img)
            }else{
                val img: Drawable? = context.getMyDrawable(R.drawable.ic_save_white_off)
                binding.ivFavorite.setImageDrawable(img)
            }
            binding.executePendingBindings()
        }
    }

    fun addItems(items: List<Product>) {
        this.items.addAll(items)
        notifyDataSetChanged()
    }

    fun addItem(item: Product) {
        this.items.add(item)
        notifyDataSetChanged()
    }

    fun clear() {
        this.items.clear()
        notifyDataSetChanged()
    }
}

 

 

 

그 안에 해쉬태그 뷰와 어댑터입니다.

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <data>

        <variable
            name="item"
            type="String" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="@dimen/margin_8dp">

        <androidx.appcompat.widget.AppCompatTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/bg_hash_tag_orange_radius_8dp"
            android:text="@{item}"
            android:textColor="@color/colorOrangeF79256"
            android:textSize="@dimen/text_size_14sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="#농촌 봉사" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
package com.mtjin.nomoneytrip.views.home

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.mtjin.nomoneytrip.R
import com.mtjin.nomoneytrip.databinding.ItemProductHashTagBinding

class ProductHashTagAdapter :
    RecyclerView.Adapter<ProductHashTagAdapter.ViewHolder>() {
    private val items: ArrayList<String> = ArrayList()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding: ItemProductHashTagBinding = DataBindingUtil.inflate(
            LayoutInflater.from(parent.context),
            R.layout.item_product_hash_tag,
            parent,
            false
        )
        return ViewHolder(
            binding
        )
    }

    override fun getItemCount(): Int = items.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        items[position].let {
            holder.bind(it)
        }
    }

    class ViewHolder(private val binding: ItemProductHashTagBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(item: String) {
            binding.item = item
            binding.executePendingBindings()
        }
    }

    fun addItems(items: List<String>) {
        this.items.addAll(items)
        notifyDataSetChanged()
    }

    fun addItem(item: String) {
        this.items.add(item)
        notifyDataSetChanged()
    }

    fun clear() {
        this.items.clear()
        notifyDataSetChanged()
    }
}

 

 

 

댓글과 공감은 큰 힘이 됩니다. 감사합니다. !!

github.com/mtjin/NoMoneyTrip

 

mtjin/NoMoneyTrip

SKT 2020 스마트 관광앱 공모전 '무전여행' 앱. Contribute to mtjin/NoMoneyTrip development by creating an account on GitHub.

github.com

 

728x90
Comments