나만의 AI/안드로이드 도와줘

Android kotlin [RecyclerView 알려줘]

정혜현 2024. 7. 5. 21:37

Q. 어떻게 사용해?

A. 

 

 

 

레이아웃

 <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/main_recycler_view"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_marginTop="70dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

 

홀더

<?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:id="@+id/item_recyclerview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context=".MainPageActivity">


    <ImageView
        android:id="@+id/iv_item_title"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_marginStart="20dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:background="@drawable/bg_round_square"
        android:clipToOutline="true"
        android:scaleType="centerCrop"
        android:src="@drawable/img_fan"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <TextView
        android:id="@+id/tv_item_title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="4dp"
        android:ellipsize="end"
        android:maxLines="2"
        android:text="제목"
        android:textSize="16sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="@+id/iv_item_like"
        app:layout_constraintStart_toEndOf="@+id/iv_item_title"
        app:layout_constraintTop_toTopOf="@+id/iv_item_title" />



</androidx.constraintlayout.widget.ConstraintLayout>

 

액티비티

 //최상단 입력
 private val adapter = Adapter(list)//어떤 어댑터인지 구체적으로 이름짓기
 //onCreate 호출
  getAdapter()
 //함수
 private fun getAdapter() {
        _binding.mainRecyclerView.adapter = adapter //리사이클러뷰와 어댑터연결
        //매니저연결
        _binding.mainRecyclerView.layoutManager = LinearLayoutManager(this)// 리니어
        _binding.mainRecyclerView.layoutManager = GridLayoutManager(this,2)// 그리드
        //그리드는 레이아웃에도 추가해줘야한다.
       
       //리사이클러뷰 디바이더
        val decoration = DividerItemDecoration(this,LinearLayoutManager.VERTICAL)
        _binding.mainRecyclerView.addItemDecoration(decoration)
    }

 

//main
val intent = Intent(this, DetailPageActivity::class.java)//클릭이벤트
        adapter = Adapter(list, itemClickListener = { item, position ->
            intent.putExtra("DATA", list[position])
            intent.putExtra("POSITION", position)
            startActivity(intent)
        }, itemLongClickListener = { position ->//롱클릭이벤트
            remove(adapter, position)
            return@Adapter true
        })

 

어댑터

class Adapter(
    private val item: MutableList<ProductInfo>,
    private val itemClickListener: (item: ProductInfo, position: Int) -> Unit,
    private val itemLongClickListener: (position: Int) -> Boolean
) : RecyclerView.Adapter<Adapter.Holder>() {
  
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Adapter.Holder {
        val binding =
            ItemRecyclerviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return Holder(binding)
    }

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

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

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

        fun bind(item: ProductInfo) {
            binding.apply {
                ivItemTitle.setImageResource(item.image)
                tvItemTitle.text = item.title
				//클릭이벤트
                itemRecyclerview.setOnClickListener {
                    itemClickListener(item, adapterPosition)
                }
                //롱클릭이벤트
                itemRecyclerview.setOnLongClickListener {
                    itemLongClickListener(adapterPosition)
                }
            }
        }
    }
}

 

 


롱클릭이벤트 : 삭제

private fun removeItem(adapter: Adapter, position: Int) {
        val builder = AlertDialog.Builder(this@MainPageActivity)
        builder.setTitle(getString(R.string.eco_market))
        builder.setMessage(getString(R.string.ask_remove))
        builder.setIcon(R.drawable.ic_logo_eco)

        val btnListener = DialogInterface.OnClickListener { dialog, which ->
            if (which == DialogInterface.BUTTON_POSITIVE) {
                adapter.notifyItemRemoved(position)
                productList.removeAt(position)
                adapter.notifyItemRangeChanged(position, adapter.itemCount)
            }
        }
        builder.setPositiveButton(getString(R.string.yes), btnListener)
        builder.setNegativeButton(getString(R.string.no), btnListener)
        builder.show()
    }
}

 


인터페이스로 만드는 방법

class Adapter(private val item: MutableList<ProductInfo>) : RecyclerView.Adapter<Adapter.Holder>() {
    //로그용
    companion object {
        private const val TAG = "Adapter" } 
	//클릭이벤트용
    interface ItemClick {
        fun onClick(view : View, position : Int)
    }
	//클릭이벤트용
    var itemClick : ItemClick? = null
    
	//★필수사항 : 홀더생성
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Adapter.Holder {
        val binding =
            ItemRecyclerviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return Holder(binding)
    }
	//★필수사항 : 홀더바인딩
    override fun onBindViewHolder(holder: Holder, position: Int) {
		//클릭이벤트용
        holder.itemView.setOnClickListener {
            itemClick?.onClick(it, position)
        }
        //1000단위
        val dec = DecimalFormat("#,###원")
		//홀더 내 뷰 연결
        holder.image.setImageResource(item[position].image)
    }
	//★필수사항
    override fun getItemCount(): Int {
        return item.size
    }
	//★필수사항 : 리사이클뷰연결
    inner class Holder(private val binding: ItemRecyclerviewBinding) :
        RecyclerView.ViewHolder(binding.root) {
        val image = binding.ivItemTitle
    }
}

 


리스트어댑터, 멀티뷰타입

 Fragment 사용시 초기화, 옵저버  onViewCreated가 아닌 onCreateView에서 해야 submitList 적용가능

//타입 설정
const val LOADING = 0
const val ITEM = 1

class HomeRecyclerViewAdapter(
   private val itemClickListener: (item: ContentModel) -> Unit
) : ListAdapter<ContentModel, ViewHolder>(diffUtil) {//뷰홀터로 지정, 객체 인자로 넘기기
//diffUtil 객체생성
    companion object {
        val diffUtil = object : DiffUtil.ItemCallback<ContentModel>() {
            override fun areItemsTheSame(oldItem: ContentModel, newItem: ContentModel): Boolean {
                return oldItem.uId == newItem.uId
            }
            override fun areContentsTheSame(oldItem: ContentModel, newItem: ContentModel): Boolean {
                return oldItem == newItem
            }
        }
    }
//타입 지정 함수
    override fun getItemViewType(position: Int): Int {
        return when(getItem(position)) {
        is ContentModel -> ITEM//타입 지정조건 설정
            else -> LOADING
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return if(viewType == ITEM) {
            val binding =
                RecyclerviewHomeHolderBinding.inflate(
                    LayoutInflater.from(parent.context),
                    parent,
                    false)
                ItemHolder(binding, itemClickListener)
        }
        else {val binding =
                RecyclerviewHomeHolderLoadingBinding.inflate(
                    LayoutInflater.from(parent.context),
                    parent,
                    false
                )
            LoadingHolder(binding)
        }
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        if(holder is ItemHolder)
            holder.bind(getItem(position))
    }

    class ItemHolder(
        private val binding: RecyclerviewHomeHolderBinding,
        private val itemClickListener: (ContentModel) -> Unit
    ) :
        ViewHolder(binding.root) {


        fun bind(item: ContentModel) {
            binding.apply {
                homeHolderTvTitle.text = item.title
                homeHolderTvDateTime.text = Util.makeDateTimeFormat(item.dateTime)
                binding.homeHolderIvSelected.isVisible = item.selectedContent
                binding.homeHolderIvVideo.isVisible = item.type != "image"
                homeHolder.setOnClickListener {
                    itemClickListener(item)
                }
            }
            Glide.with(itemView.context)
                .load(item.thumbnail)
                .into(binding.homeHolderIvTitle)
        }
    }
}

class LoadingHolder(
    private val binding: RecyclerviewHomeHolderLoadingBinding
) :
    ViewHolder(binding.root) {
    fun bind(item: ContentModel) {
        binding.apply {
        }
    }
}