[Andorid] UMC Study - 5주차

ListView

https://velog.io/@sjlim/Andorid-UMC-Study-3%EC%A3%BC%EC%B0%A8
마지막 장 ListView 참조!

RecyclerView

  • 화면안에 들어갈 한정된 수의 뷰를 유지함으로써 매우 효율적으로 스크롤 할 수 있음

  • 리스트뷰와 다르게 재활용이 가능한 뷰

  • 아래로 스크롤 할때마다 맨위에 존재하는 뷰객체를 아래쪽에 나타날 뷰 위치로 객체를 이동시키는 즉, 재사용하는 하는 동작 방식

  • 이때 맨 처음 뷰객체를 기억하고 있을 뷰홀더가 필요하고 어댑터레이아웃매니저가 필요

1) LayoutManager

  • 아이템 View의 크기 및 위치를 결정해 주는 역할 수행

ex) LinearLyaoutManager

recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
// context, 방향(가로/세로), reverse layout 여부

2) Adapter

  • RecyclerView에 표시 될 View를 공급하는 클래스
  • 3가지 메소드를 오버라이딩

onCreateViewHolder : ViewHolder 생성하여 반환
onBindViewHolder : ViewHoler에 값을 설정
getItemcount : 아이템의 개수 반환

3) ViewHolder

  • RecyclerView.ViewHolder 클래스
  • RecyclerView에 배치되는 View의 설정을 담당
  • onCreateViewHolder에 의해 생성

4) 데이터 리스트 예제

  1. Album 데이터 클래스 생성 및 정보 관리
data class Album (
    var title: String? = "",
    var singer: String? = "",
    var coverImg: Int? = null,
    var songs: ArrayList<Song>? = null
)
  1. 더미데이터 생성
private var albumDatas = ArrayList<Album>();

albumDatas.apply {
      add(Album("Butter", "방탄소년단 (BTS)", R.drawable.img_album_exp))
      add(Album("Lilac", "아이유 (IU)", R.drawable.img_album_exp2))
      add(Album("Next Level", "에스파 (AESPA)", R.drawable.img_album_exp5))
      add(Album("Boy with Luv", "방탄소년단(BTS)", R.drawable.img_album_exp3))
      add(Album("City", "오왼 (Owen)", R.drawable.img_album_exp6))
      add(Album("고해", "오왼 (Owen)", R.drawable.img_album_exp4))
}
  1. 리사이클러뷰의 한 행을 채워줄 아이템 레이아웃 생성 (item_album.xml)
<?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_marginLeft="10dp"
    android:layout_marginRight="10dp">

    <androidx.cardview.widget.CardView
        android:id="@+id/item_album_cover_img_cv"
        android:layout_width="150dp"
        android:layout_height="150dp"
        app:cardCornerRadius="7dp"
        app:cardElevation="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <ImageView
            android:id="@+id/item_album_cover_iv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/img_album_exp2"
            android:scaleType="fitCenter"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
    </androidx.cardview.widget.CardView>

    <ImageView
        android:id="@+id/item_album_play_iv"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="5dp"
        android:src="@drawable/widget_black_play"
        app:layout_constraintBottom_toBottomOf="@id/item_album_cover_img_cv"
        app:layout_constraintEnd_toEndOf="parent"/>

    <TextView
        android:id="@+id/item_album_title_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="LILAC"
        android:textSize="20sp"
        android:textColor="@color/black"
        android:layout_marginTop="10dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/item_album_cover_img_cv"/>

    <TextView
        android:id="@+id/item_album_singer_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="아이유 (IU)"
        android:textSize="15sp"
        android:layout_marginTop="3dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/item_album_title_tv"/>

</androidx.constraintlayout.widget.ConstraintLayout>
  1. Activity에서 RecyclerView의 LayoutManager 관리
binding.homeTodayAlbumRv.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
  1. Adapter 생성
  • 리사이클러뷰와 item을 한줄씩 맵핑시키고, 데이터를 넣어주는 역할을 함
  • Adapter 클래스를 상속받아서 만듦
class AlbumRVAdapter(private val albumList: ArrayList<Album>) :
    RecyclerView.Adapter<AlbumRVAdapter.ViewHolder>() {
    
    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): AlbumRVAdapter.ViewHolder {
        val binding: ItemAlbumBinding = ItemAlbumBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup,false)

        return ViewHolder(binding)
    }

    // 아이템 뷰 홀더에 데이터 바인딩
    override fun onBindViewHolder(holder: AlbumRVAdapter.ViewHolder, position: Int) {
        holder.bind(albumList[position])
    
    }

    // data set 크기를 알려주는 함수 => 리사이클러뷰의 마지막이 어디인지 알 수 있음
    override fun getItemCount(): Int = albumList.size

    // ViewHolder, inner class로 생성
    inner class ViewHolder(val binding: ItemAlbumBinding) : RecyclerView.ViewHolder(binding.root) {

        fun bind(album : Album) {
            binding.itemAlbumTitleTv.text = album.title
            binding.itemAlbumSingerTv.text = album.singer
            binding.itemAlbumCoverIv.setImageResource(album.coverImg!!)
        }
    }
}
  1. 어댑터 연결
       // 어댑터 설정
        val albumRVAdapter = AlbumRVAdapter(albumDatas)

        // rv와 adapter 연결
        binding.homeTodayAlbumRv.adapter = albumRVAdapter

5) RecyclerView에서의 Click Listener

  1. Adapter에서 인터페이스 정의
// step 1
    interface MyItemClickListener{
        fun onItemClick(album : Album)
        fun onRemoveAlbum(position: Int)
    }

    // listener 객체 전달 받는 함수 & 저장하는 변수
    private lateinit var mItemClickListener: LockerSaveRVAdapter.MyItemClickListener

    fun setMyItemClickListener(itemClickListener: LockerSaveRVAdapter.MyItemClickListener){
        mItemClickListener = itemClickListener
    }
    
    fun removeItem(position: Int) {
        albumList.removeAt(position)
        notifyDataSetChanged()
    }
  1. ViewHolder를 통해 itemView에 접근 해 리스너 달기

// step 2
       holder.itemView.setOnClickListener {
            mItemClickListener.onItemClick(albumList[position])
       }
       holder.binding.itemSaveMoreIb.setOnClickListener {
            mItemClickListener.onRemoveAlbum(position)
       }
  1. Activity(Fragment)에서 adapter의 인터페이스 구현
// step 3
saveRVAdapter.setMyItemClickListener(object: LockerSaveRVAdapter.MyItemClickListener{
      override fun onItemClick(album: Album) {

      }

      override fun onRemoveAlbum(position: Int) {
                saveRVAdapter.removeItem(position)
      }
})

more 버튼 클릭하면 data 삭제되게 구현!

좋은 웹페이지 즐겨찾기