[Android] RecyclerView

June·2023년 7월 15일
0

RecyclerView

RecyclerView 와 ListView 차이

RecyclerViewListView는 안드로이드에서 아이템 목록을 표시하는 위젯으로 기능적으로는 유사하다. 리스트뷰는 과거에 많이 사용되었지만, 현재 대부분 리사이클러뷰를 권장한다.


RecyclerView

  • 화면에 보이는 아이템만 메모리에 로드하여 효율적으로 동작
  • Layout Manager를 통해 세로 스크롤 형태 뿐만아니라 그리드 형태, 뷰페이좌 유사한 페이징 형태 등 다양한 레이아웃을 구현
  • ViewHolder 패턴을 반드시 사용하여 뷰의 재활용을 통해 부드러운 스크롤링을 도와주며 메모리 관리 개선
  • 아이템 추가, 제거, 이동 등 애니메이션을 기본적으로 지원. 아이템 클릭, 롱클릭 이벤트 등 다양한 방식으로 처리할 수 있다

ListView

  • 모든 아이템을 한 번에 메모리에 로드하여 화면에 표시
  • 단순히 세로 스크롤 형태의 리스트만 제공
  • 리스트뷰도 ViewHolder 패턴을 사용할 수 있지만 강제성은 없다
  • 애니메이션을 직접 구현하여 사용

RecyclerView 사용

RecyclerView에 표시할 아이템 목록 준비

 val data1 = arrayOf("토고", "프랑스", "스위스", "스페인", "일본", "독일", "브라질", "대한민국",
        "토고", "프랑스", "스위스", "스페인", "일본", "독일", "브라질", "대한민국")
        
 val imgRes = intArrayOf(
        R.drawable.imgflag1 , R.drawable.imgflag2 , R.drawable.imgflag3 ,
        R.drawable.imgflag4 , R.drawable.imgflag5 , R.drawable.imgflag6 ,
        R.drawable.imgflag7 , R.drawable.imgflag8, R.drawable.imgflag1 , R.drawable.imgflag2 , R.drawable.imgflag3 ,
        R.drawable.imgflag4 , R.drawable.imgflag5 , R.drawable.imgflag6 ,
        R.drawable.imgflag7 , R.drawable.imgflag8
    )

상속받지 않은 AdapterClass 생성

inner class RecyclerAdapterClass() {

}

ViewHolderClass 생성

  • RecyclerView의 Row 하나가 가지고 있는 View들의 객체를 가지고있는 HolderClass
  • 주 생성자로 ViewBinding 객체를 받는다
  • 부모의 생성자에게 행 하나로 사용할 View를 전달
inner class ViewHolderClass(rowBinding: RowBinding) : ViewHolder(rowBinding.root) {

}

AdapterClass를 RecyclerView.Adapter를 상속

  • 상속받은 후 AdapterClass의 implement members
inner class RecyclerAdapterClass : RecyclerView.Adapter<RecyclerAdapterClass.ViewHolderClass>(){

	inner class ViewHolderClass(rowBinding: RowBinding) : ViewHolder(rowBinding.root) {

	}
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderClass {
    
    }
    
    override fun getItemCount(): Int {
            
    }
    
    override fun onBindViewHolder(holder: ViewHolderClass, position: Int) {
    
    }
}

onCreateViewHolder()

  • ViewHolder의 객체를 생성해서 반환
  • 전체 Row의 개수가 아닌 필요한 만큼만 Row로 사용할 View를 만들고 ViewHolder도 생성

getItemCount()

  • 전체Row의 개수를 반환

onBindViewHolder()

  • ViewHolder를 통해 View에 접근하여 View에 값을 설정
  • 첫 번째 매개변수 : ViewHolder 객체
  • 두 번째 매개변수 : 특정 row의 순서값

전체코드

    inner class RecyclerAdapterClass : RecyclerView.Adapter<RecyclerAdapterClass.ViewHolderClass>(){

        inner class ViewHolderClass(rowBinding: RowBinding) : ViewHolder(rowBinding.root), OnClickListener {

			 // 행 하나를 구성하는 View 중 개발자가 사용하고자 하는 View 객체를 담을 변수
            var textViewRow : TextView
            var imageViewRow : ImageView

			// 사용할 view를 변수에 담아준다
            init{
                textViewRow = rowBinding.textViewRow
                imageViewRow = rowBinding.imageViewRow
            }

			// 아이템 row 클릭 이벤트
            override fun onClick(p0: View?) {
                // ViewHolder를 통해 항목의 순서값을 가지고 온다
                activityMainBinding.run {
                    textView.run {
                        text = data1[adapterPosition]
                    }
                }
            }
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderClass {

            // ViewBInding
            val rowBinding = RowBinding.inflate(layoutInflater)
            // ViewHolder
            val viewHolderClass = ViewHolderClass(rowBinding)

            // 클릭 이벤트를 설정
            rowBinding.root.setOnClickListener(viewHolderClass)

            // 항목 View의 가로 세로 길이를 해당구역 터치하기 위해 설정 (가로 , 세로)
            val params = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)
            rowBinding.root.layoutParams = params

            return viewHolderClass
        }

        // 전체Row의 개수를 반환
        override fun getItemCount(): Int {
            return imgRes.size
        }

        // ViewHolder를 통해 View에 접근하여 View에 값을 설정
        // 첫 번째 매개변수 : ViewHolder 객체
        // 두 번째 매개변수 : 특정 row의 순서값
        override fun onBindViewHolder(holder: ViewHolderClass, position: Int) {
            holder.textViewRow.text = data1[position]
            holder.imageViewRow.setImageResource(imgRes[position])
        }
    }

onCreate() adapter 설정

	activityMainBinding.run {
		recyclerView.run {
			adapter = RecyclerAdapterClass()

			// RecyclerView의 항목을 어떤 방식으로 보여줄지 정해준다
			// LinareLayout - 위에서 아래 방향으로
			layoutManager = LinearLayoutManager(this@MainActivity)

			// Grid - 한줄에 몇 칸을 사용할 것인지
			// layoutManager = GridLayoutManager(this@MainActivity,2)

			// 항목 View의 크기가 다를 경우 GridLayoutManager는 같은 행의 모든 뷰가 같은 크기로 조정되지만
			// StaggeredGridLayoutManager는 항목 View의 크기는 필요한 만큼만 사용하고 화면에 빈칸이 없도록 배치를 조정해준다
			// layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
          }
      }

데이터 갱신

  • 데이터가 변경되면 notifyDataSetChanged() 메서드를 호출하여 RecyclerView를 업데이트
adapter.notifyDataSetChanged()

row 롱클릭시 ContextMenu

  • res - menu context_menu 레이아웃 생성
  • ViewHolderClass에 코드 추가
rowMainBinding.root.setOnCreateContextMenuListener { menu, view, menuInfo ->
	// ContextMenu 타이틀 설정
	menu.setHeaderTitle("ContextMenu 타이틀")
    // ContextMenu 레이아웃 설정
	activity?.menuInflater?.inflate(R.menu.context_menu, menu)
	// context_menu 레이아웃에 세팅한 아이템 순서대로 0, 1
	menu[0].setOnMenuItemClickListener {
    	// 선택한 메뉴의 동작 코드
    }
                  
	menu[1].setOnMenuItemClickListener {
		// 선택한 메뉴의 동작 코드
    }
}
profile
끝까지 해보자

0개의 댓글