Front-End/Kotlin

[Kotlin] Viewpager2, Recycler View, Layout Manager

psy_er 2024. 4. 25. 14:49
728x90

[Kotlin] Viewpager2, Recycler View, Layout Manager

 

 

< ViewPager2 >

오랫동안 이용했던 viewpager와 별개로 2019년에 viewpager2를 제공하였다.

항목이 순서대로 나열되어 있는데 한 화면에 항목 하나가 나온다는 개념이다. 

 

어댑터 : 여러 프래그먼트가 포함된 뷰를 제어할 수 있는 것으로 각 항목을 만들어 주는 역할을 한다.

프래그먼트 어댑터 이용 : 프래그먼트로 작성했으면 FragmentStateAdapter로 뷰 페이저 2를 구현 한다.

class MyFragmentPagerAdapter(activity: FragmentActivity): FragmentStateAdapter(activity)
{
   val fragments: List<Fragment>
   init{
      fragments = listOf(OneFragment(), TwoFragment(), ThreeFragment())
      Log.d("kkang", "fragments size : ${fragments.size}")
   }
   override fun getItemCount() : Int = fragments.size
   override fun createFragment(position: Int): Fragment = fragments[position]
}

 

 

 

build.gradle에 dependencies 추가

dependencies {

    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.appcompat)
    implementation("androidx.viewpager2:viewpager2:1.0.0")
    implementation(libs.material)
    implementation(libs.androidx.activity)
    implementation(libs.androidx.constraintlayout)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
}

 

프래그먼트를 집어넣는 것은 mainActivity에서 코드를 짠다.

 

< 리사이클러 뷰 >

리사이클러 뷰 기초 사용법

 

구성요소

ViewHolder(필수) : 항목에 필요한 뷰 객체를 가집니다, 리사이클러 뷰 한 칸을 의미한다.

Adapter(필수) : 항목을 구성합니다. 각 항목을 만들어 주는 역할을 한다.

LayoutManager(필수) : 항목을 배치합니다.

ItemDecoration(옵션) : 항목을 꾸밉니다.

 

리사이클러 뷰도 아이템 항목을 다루고 있기 때문에 Adapter가 있어야 합니다.

DB 내용을 리사이클러 뷰항목에 넣을 예정이다.

 

뷰 홀더 준비

- 각 항목에 해당하는 뷰 객체를 가지는 뷰 홀더는 RecyclerView.ViewHolder를 상속받아 작성

class MyViewHolder(val binding: ItemMainBinding): RecyclerView.ViewHolder(binding.root)

 

어댑터 준비

- 각 항목을 만들어 주는 역할을 한다

 

getItemCount() : 항목 개수를 판단하려고 자동으로 호출됩니다.

onCreateViewHolder() : 항목의 뷰를 가지는 뷰 홀더를 준비하려고 자동으로 호출됩니다.

onBindViewHolder() : 뷰 홀더의 뷰에 데이터를 출력하려고 자동으로 호출됩니다.

 

class MyAdapter(val binding: ItemMainBinding):
   RecyclerView.Adapter<RecyclerView.ViewHolder>(){
   
   // 항목의 개수 구하기
   override fun getItemCount(): Int = datas.size
   
   // 항목 구성에 필요한 뷰 홀더 객체 준비
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
   RecyclerView.ViewHolder = MyViewHolder(ItemMainBinding.inflate(LayoutInflater.from(parent.context),parent, false)) 
   
   // 뷰에 데이터 출력
   override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int){
      val binding = (holder as MyViewHolder).binding
      
      // 뷰에 데이터 출력
      binding.itemData.text = datas[position]
      // 뷰에 이벤트 추가
      binding.itemRoot.setOnClickListener{
      }
   
   }}

 

RecyclerView.Adapter를 상속받아 getItemCount(), onCreateViewHolder(), onBindViewHolder() 오버라이드 함수를 반드시 포함시켜야 한다. ItemMainBinding XML 파일에서 아이템을 어떻게 배치할 것인지 정하고, ViewHolder 클래스를 정의하여 onCreateViewHolder에서 사용한다.

 

[필수] Adapter와 ViewHolder 클래스 작성하기

class MyViewHolder(val binding:ItemRecyclerviewBinding) : RecyclerView.ViewHolder(binding.root)
class MyAdapter(val datas:MutableList<String>): RecyclerView.Adapter<RecyclerView.ViewHolder>(){
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return MyViewHolder(ItemRecyclerviewBinding.inflate(LayoutInflater.from(parent.context),parent,false))
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val binding = (holder as MyViewHolder).binding
        binding.itemData.text = datas[position]
    }

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

 

 

리사이클러 뷰 출력

class RecyclerViewActivity : AppCompatActivity(){
   override fun onCreate(savedInstanceSTate: Bundle?){
      super.onCreate(savedInstanceState)
      val binding = ActivitiyRecyclerViewBinding.inflate(layoutInflater)
      setContentView(binding.root)
      
      val datas = mutableListOf<String>()
      for(i in 1..10){
         datas.add("item $i")
      }
      binding.recyclerView.layoutManager = LinearLayoutManager(this)
      binding.recyclerView.adapter = MyAdapter(datas)
      binding.recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayout Manager.VERTICAL))
   }
}

 

항목을 동적으로 추가/제거

항목을 구성하는 데이터에 새로운 데이터를 추가하거나 제거한 후 어댑터의 notifyDataSetChanged() 함수를 호출

datas.add("new data")
adapter.notifyDataSetChanged()

 

 

< 레이아웃 매니저로 배치 >

레이아웃 매니저는 어댑터로 만든 항목을 리사이클러 뷰에 배치합니다.

- LinearLayoutManager : 항목을 가로나 세로 방향으로 배치합니다.  디폴트가 vertical이다.

- GridLayoutManager : 항목을 그리드로 배치합니다.

- StaggeredGridLayoutManager : 항목을 높이가 불규칙한 그리드로 배치합니다.

 

항목을 세로 방향으로 배치

binding.recyclerView.layoutManager = 
   LinearLayoutManager(this)

 

항목을 가로 방향으로 배치

val layoutManager = LinearLayoutManager(this)
layoutManager.orientation = LinearLayoutManager.HORIZONTAL
binding.recyclerView.layoutManager = layoutManager

 

 

< 그리드로 배치 >

GridLayoutManager를 이용하면 한 줄에 두 개 배치도 가능합니다.

생성자의 숫자는 그리드에서 열의 개수를 뜻합니다.

방향을 설정할 수 있습니다.

 

가로로 설정하려면 생성자에 GridLayoutManager.HORIZONTAL을 지정해야 합니다.

val layoutManager = GridLayoutManager(this, 3, GridLayoutManager.HORIZONTAL, false)
binding.recyclerView.layoutManager = layoutManager

 

 

< 아이템 데코레이션 >

아이템 데커레이션은 리사이클러 뷰를 다양하게 꾸밀 때 사용한다. 항목의 구분선을 출력해 주는 DividerItem Decoration이다. ItemDecoration을 상속받는 개발자 클래스를 만들고 이 클래스에서 다양한 꾸미기 작업을 합니다.

 

onDraw() : 꾸미고 배치, 항목이 배치되기 전에 호출됩니다. 그러고 나서 리사이클러 뷰를 배치합니다.

onDrawOver() : 배치 후 꾸미기, 항목이 모두 배치된 후 호출됩니다. 배치하고 나서 그림을 그립니다.

getItemOffsets() : 각각의 항목을 꾸며준다.

 

class MyItemDecoration(val context: Context):RecyclerView.ItemDecoration(){
    // 꾸미고 배치
    override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        // 그림 -> 항목
        super.onDraw(c, parent, state)
        c.drawBitmap(BitmapFactory.decodeResource(context.resources, R.drawable.kbo),
            0f, 0f, null)
    }

    // 배치 후 꾸미기
    override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        // 항목 -> 그림
        super.onDrawOver(c, parent, state)
        c.drawBitmap(BitmapFactory.decodeResource(context.resources, R.drawable.kbo),
            500f, 500f, null)
    }

    // 각각의 item에 대해서 꾸며준다. 근데 recyclerview에서 바로 변경 가능한 부분.
    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        super.getItemOffsets(outRect, view, parent, state)
        view.setBackgroundColor(Color.parseColor("#123456"))
    }
}
728x90