GDSC HUFS 3기/Android with Kotlin Team 1

[1팀] 14-10. 화면 구성하기 : 탭메뉴 뷰페이저와 리사이클러 뷰

dev-yen 2021. 11. 16. 22:54

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

작성자 : 김예은

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

 

 

⬇먼저 확인하기⬇

📌리사이클러 뷰 개념

 

1. 리사이클러 뷰를 활용해 스와이프 뷰 만들기

layout 설정

  • 뷰페이저와 TabLayout을 화면에 배치시킨다.
  • RecyclerView에서 아이템으로 사용할 layout을 만들어준다. (item_viewpager)

 

*MainActivity 코드

package com.example.viewpagerfragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.example.viewpagerfragment.databinding.ActivityMainBinding
import com.example.viewpagerfragment.databinding.ItemViewpagerBinding
import com.google.android.material.tabs.TabLayoutMediator

class MainActivity : AppCompatActivity() {

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

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

        with(binding) {
            //1. 데이터 로드
            val list = listOf("월","화","수","목","금","토","일")
            //2. 어뎁터 생성
            val pagerAdapter = CustomPagerAdapter(list)
            //3. 어뎁터와 뷰페이저 연결
            viewPager.adapter = pagerAdapter
            //4. 탭 타이틀 목록 생성. 위의 list 데이터 사용
            //5. 탭레이아웃과 뷰페이저 연결
            TabLayoutMediator(tabLayout, viewPager){tab, position->
                tab.text = list.get(position)

            }.attach()
        }
    }
}

class Holder(val binding:ItemViewpagerBinding) : RecyclerView.ViewHolder(binding.root){
    fun setItem(text: String){
        binding.textView.text = text
    }
}

class CustomPagerAdapter(val textList:List<String>) :RecyclerView.Adapter<Holder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        val binding = ItemViewpagerBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return Holder(binding)
    }
    override fun onBindViewHolder(holder: Holder, position: Int) {
        holder.setItem(textList.get(position))
    }
    override fun getItemCount() = textList.size
}
  • RecyclerView의 Adapter를 상속받는 CustomPagerAdapter를 만든다.
  • getItemCount() 메서드가 페이지를 몇 개 만들지 알아낸다.
  • onCreateViewHolder() 메서드가 필요한 페이지들을 만든다.
  • onBindViewHolder() 메서드가 각 페이지에 맞는 데이터를 띄운다.
  • TabLayoutMediator
    • 탭 레이아웃을 뷰페이저와 연결하는 중재자.
      • 중재자는 탭이 선택될 때 뷰페이저의 위치를 선택한 tab과 동기화하고 사용자가 뷰페이저를 끌 때 탭 레이아웃의 스크롤 위치를 동기화한다.
      • 뷰페이저가 이동할 때 탭을 조정하기 위해 뷰페이저의 onPageChangeCallback을 수신한다.
        (그래서 화면이 스와이프 될 때 바로바로 반응한다)
      • 이 클래스의 인스턴스를 만들어 링크를 설정하고 뷰페이저에 어댑터가 있는지 확인한 다음 이를 호출(.attach()) 한다.

 

2. data class 사용해보기

data class 란?

데이터를 전달하기위해 사용하는 객체로, DTO를 편리하게 선언할 수 있도록 하는 클래스이다.

데이터를 표현하는 객체는 getter(), setter(), toString() 등의 메서드를 지원해야 한다. 그러나 코틀린에선 data class 를 쓰면 알아서 이런 메서드를 정의해준다.

data class Page(var day: Int, var weather: String)
  • 주 생성자는 최소한 하나의 매개변수를 가져야 한다.
  • 주 생성자에는 var 또는 val로 선언된 프로퍼티만 존재해야 한다.
  • 데이터 클래스에는 abstract, open 등의 키워드를 사용할 수 없다.

 

data class를 사용한 리사이클러 뷰 - 뷰페이저

*MainActivity Code

package com.example.viewpagerfragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.example.viewpagerfragment.databinding.ActivityMainBinding
import com.example.viewpagerfragment.databinding.ItemViewpagerBinding
import com.google.android.material.tabs.TabLayoutMediator

class MainActivity : AppCompatActivity() {

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

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

        with(binding) {
            //1. 데이터 로드
            val list = loadData()
            //2. 어뎁터 생성
            val pagerAdapter = CustomPagerAdapter(list)
            //3. 어뎁터와 뷰페이저 연결
            viewPager.adapter = pagerAdapter
            //4. 탭 타이틀 목록 생성. 위의 list 데이터 사용
            val titles = listOf("월","화","수","목","금","토","일")
            //5. 탭레이아웃과 뷰페이저 연결
            TabLayoutMediator(tabLayout, viewPager){tab, position->
                tab.text = titles.get(position)

            }.attach()
        }
    }

    fun loadData() : List<Page> {
        val pageList = mutableListOf<Page>()
        pageList.add(Page(1, "흐림"))
        pageList.add(Page(2, "맑음"))
        pageList.add(Page(3, "구름"))
        pageList.add(Page(4, "비"))
        pageList.add(Page(5, "눈"))
        pageList.add(Page(6, "태풍"))
        pageList.add(Page(7, "안개"))
        return pageList
    }
}

class Holder(val binding:ItemViewpagerBinding) : RecyclerView.ViewHolder(binding.root){
    fun setItem(page: Page){
        with(binding){
            textDay.text = "${page.dat} 일"
            textWeather.text = page.weather
        }
    }
}


class CustomPagerAdapter(val pageList:List<Page>) :RecyclerView.Adapter<Holder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        val binding = ItemViewpagerBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return Holder(binding)
    }
    override fun onBindViewHolder(holder: Holder, position: Int) {
        holder.setItem(pageList.get(position))
    }
    override fun getItemCount() = pageList.size
}

data class Page(val day:Int, val weather: String)
  • loadData를 Page data class를 사용하는 데이터로 바꾸었다.
  • CustomPagerAdapter는 이 Page 클래스 데이터를 받아서 개수를 산정하고, 해당 개수만큼 onCreateViewHolder()로 item_layout을 사용한다.