GDSC HUFS 3기/Android with Kotlin Team 1

[1팀] 14-4. 화면 구성하기: 리사이클러뷰

이승민👨‍💻 2021. 11. 16. 22:53

이 글은 이것이 안드로이드다 with 코틀린(개정판)를 참고하여 작성하였습니다.

작성자 : 이승민

개발환경은 Windows, Android Studio입니다.

 

1. 리사이클러뷰(RecyclerView)란?

  • 리스트뷰(ListView)와 유사하게 여러 가지 항목을 나열하는 목록 화면을 만들 때 사용
  • 리스트뷰와 차이점??
    • 기존의 리스트뷰는 스크롤을 내릴 때, 화면에서 사라지는 가장 위의 아이템을 삭제하고 가장 아래에 아이템을 생성하여 성능 저하가 발생할 수 있다.
    • 리사이클러뷰는 가장 위의 아이템을 삭제하지 않고 가장 아래의 아이템쪽으로 객체를 이동시켜 재활용을 한다.

2. 리사이클러뷰 구성 요소

  • ViewHolder(필수) : 항목에 필요한 뷰 객체
  • Adapter(필수) : 항목을 구성
  • LayoutManager(필수) : 항목을 배치
  • ItemDecoration(옵션) : 항목을 꾸밈

리사이클러뷰의 각 구성 요소

3. 리사이클러뷰 프로그래밍 순서

  • 일반적으로 다음과 같은 절차를 통해 리사이클러뷰를 사용할 수 있다.
  1. 리사이클러뷰가 표시될 위치 결정 (MainActivity에 RecyclerView 추가)
  2. 리사이클러뷰 아이템 배치 형태 결정 (아이템 뷰 화면 설계 및 LayoutManager 선택)
  3. 아이템 뷰 레이아웃 구성 (레이아웃 XML 작성)
  4. 아이템 데이터 클래스 정의
  5. 어댑터 상속 및 구현 (extends RecyclerView.Adapter)
  6. 뷰홀더 상속 및 구현 (extends RecyclerView.ViewHolder)
  7. 어댑터 생성 및 지정 (RecyclerView.setAdapter())
  8. 레이아웃 매니저 생성 및 지정 (RecyclerView.setLayoutManager())
  9. 데이터 추가 및 아이템 표시 (RecyclerView.Adapter.notifyDataSetChanged())

4. 아이템 레이아웃, 데이터 클래스 생성 후 초기 설정

아이템 레이아웃 생성

  • res → layout 우클릭 → new → Layout Resource File → 이름 설정 (item_recycler), Root element 설정(LinearLayout)

데이터 클래스 생성

  • 패키지 우클릭 → New → Kotlin Class/File → Data Class
  • // Memo.kt
    package com.example.recyclerview
    
    data class Memo(var no:Int, var title:String, var timestamp:Long)

activity_main.xml
item_recycler.xml

5. MainActivity 코드

// MainActivity.kt
class MainActivity : AppCompatActivity() {

    val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        // 어댑터를 생성하는 순서
        // 1. 데이터를 불러오고
        val data = loadData()
        // 2. 어댑터를 생성
        val customAdapter = CustomAdapter(data)
        // 3. 화면의 RecyclerView와 연결
        binding.recyclerView.adapter = customAdapter
        // 4. 레이아웃 매니저 설정
        binding.recyclerView.layoutManager = LinearLayoutManager(this)
    }

    fun loadData() : MutableList<Memo> {
        val memoList = mutableListOf<Memo>()
        for(no in 1..100) {
            val title = "이것이 안드로이드다 $no"
            val date = System.currentTimeMillis()
            val memo = Memo(no, title, date)
            memoList.add(memo)
        }
        return memoList
    }
}

class CustomAdapter(val listData:MutableList<Memo>) : RecyclerView.Adapter<CustomAdapter.Holder>() {
    // ctrl + i 로 필수 메소드 3개 구현
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        val binding = ItemRecyclerBinding.inflate(LayoutInflater.from(parent.context), parent, false) // 거의 고정
        return Holder(binding)
    }

    override fun getItemCount() = listData.size

    override fun onBindViewHolder(holder: Holder, position: Int) {
        // 1. 사용할 데이터를 꺼내고
        val memo = listData.get(position)
        // 2. 홀더에 데이터를 전달
        holder.setMemo(memo)
    }


    class Holder(val binding:ItemRecyclerBinding):RecyclerView.ViewHolder(binding.root) {
        lateinit var currentMemo:Memo
        // 클릭처리는 init에서만 한다
        init {
            binding.root.setOnClickListener {
                val title = binding.textTitle.text
                Toast.makeText(binding.root.context, "클릭된 아이템 : ${currentMemo.title}", Toast.LENGTH_SHORT).show()
            }
        }

        // 3. 받은 데이터를 화면에 출력
        fun setMemo(memo:Memo) {

            currentMemo = memo

            with(binding) {
                textNo.text = "${memo.no}"
                textTitle.text = memo.title

                val sdf = SimpleDateFormat("yyyy-MM-dd")
                val formattedDate = sdf.format(memo.timestamp)
                textDate.text = formattedDate
            }
        }
    }
}