Front-End/Kotlin

[Kotlin] Material 라이브러리, 플로팅 버튼, Tab 레이아웃, 뷰페이저

psy_er 2024. 4. 26. 16:03
728x90

[Kotlin] Material 라이브러리, 플로팅 버튼, Tab 레이아웃, 뷰페이저

 

< ViewPager2 >

이전에 사용되었던 viewpager와 별개로 2019년에 viewpager2를 제공하였다.

항목이 순서대로 나열되어 있는데 한 화면에 항목 하나가 나오는 것을 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)
}

 

 

< 리사이클러 뷰 >

리사이클러 뷰 기초 사용법

 

구성요소

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
    }
}

 

 

< 머티리얼 라이브러리 >

 

머티리얼 라이브러리란? 구글의 머티리얼 디자인은 모바일과 데스크톱, 그리고 그 밖에 다양한 장치를 아우르는 일관된 애플리케이션 디자인 지침입니다. 안드로이드의 머티리얼 라이브러리는 디자인 가이드라인이라고 생각하면 쉽게 이해할 수 있습니다. 코틀린에서 플로팅 버튼과 리사이클러 뷰를 연결시켜 보는 작업을 해봅시다.

 

<플로팅 버튼>

먼저 플로팅 버튼은 앱 화면 내 오른쪽 아래있는 버튼처럼 더 많은 정보를 수집할 수 있는

화면에 떠있는 듯한 버튼을 의미합니다.

 

 

플로팅 버튼

    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
        android:id="@+id/main_fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="30dp"
        app:icon="@android:drawable/ic_input_add"
        android:text="Add Item"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"/>

 

확장된 플로팅 액션 버튼 조절

binding.extendedFab.setOnClickListener{
   when(binding.extendedFab.isExtended){
      true -> binding.extendedFab.shrink()
      false -> binding.extendedFab.extend()
   }
}

 

 

< 탭 레이아웃 >

 

탭 레이아웃은 탭 tab으로 구분하는 화면에서 탭 버튼을 배치하는 레이아웃입니다.

탭을 클릭해서 fragment를 이동할 수 있습니다.

 

XML 파일에서 탭 버튼 정의

- 탭 버튼을 코드에서 정의하지 않고 레이아웃 XML 파일의 TabItem으로 정의합니다.

<com.google.android.material.tabs.TabLayout
   <com.google.android.material.tabs.TabItem
      android:text="Tab1" />
   <com.google.android.material.tabs.TabItem
      android:text="Tab2" />
   <com.google.android.material.tabs.TabItem
      android:text="Tab3" />
</com.google.android.material.tabs.TabLayout>

 

탭 버튼의 이벤트 핸들러를 생성하여 이벤트 처리를 합니다.

tabLayout.addOnTabSelectedListener(object: TabLayout.OnTabSelectedListener{
   override fun onTabSelected(tab: TabLayout.Tab?){
      val transaction = supportFragmentManager.beginTransaction()
      when(tab?.text){
         "Tab1" -> transaction.replace(R.id.tabContent, OneFragment())
         "Tab2" -> transaction.replace(R.id.tabContent, TwoFragment())
         "Tab3" -> transaction.replace(R.id.tabContent, ThreeFragment())
      }
      transaction.commit()
   }
   // 선택된 탭 버튼을 다시 선택할 때 이벤트
   override fun onTabReselected(tab: TabLayout.Tab?){
   }
   // 다른 탭 버튼을 눌러 선택된 탭 버튼이 해제될 때 이벤트
   override fun onTabUnselected(tab: TabLayout.Tab?){
   }
})

 

- 탭 버튼 정렬하기

tabGravity는 탭 버튼을 정렬하는 속성입니다.

 

- 스크롤 설정하기

tabMode 속성은 탭 버튼을 스크롤할 수 있는지를 설정할 수 있습니다.

fixed은 스크롤을 지원하지 않는다는 의미입니다.

scrollable로 설정하면 탭 버튼이 왼쪽부터 나열되고 모두 출력할 수 없다면 자동으로 가로 스크롤이 생성됩니다.

 

 

- 탭 레이아웃과 뷰 페이저 연동하기

TabLayout과 ViewPager2를 등록한 후 코드에서 TabLayoutMediator를 이용해 둘을 연동합니다.

프레그먼트들을 뷰페이저 2에 담고 있는 것은 액티비티 메인입니다.

액티비티 메인에 뷰페이저 2와 Tablayout을 만들면 됩니다.

 

- 탭 레이아웃과 뷰 페이저 등록

<LinearLayout
    <androidx.viewpager2.widget.ViewPager2
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/viewpager">
    </androidx.viewpager2.widget.ViewPager2>

    <com.google.android.material.tabs.TabLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tabs" />
</LinearLayout>

 

- 탭 레이아웃과 뷰 페이저 연동

TabLayoutMediator(tabLayout, viewPager){tab, position ->
   tab.text = "Tab${(position + 1)}"
}.attch()

 

 

뷰페이저의 배치가 화면 전체를 차지할 때

<LinearLayout
    <!-- LinearLayout에서는 배치하는 순서에 맞춰서 배치된다 -->
    <!-- viewpager가 화면을 다써서 탭이 보이지 않는다 -->
    <!-- android:layout_height="0dp"
         android:layout_weight="1" 설정하면 먼저 tab 지정, 남은 부분 뷰페이저-->

    <androidx.viewpager2.widget.ViewPager2
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/viewpager">
    </androidx.viewpager2.widget.ViewPager2>

    <com.google.android.material.tabs.TabLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tabs" />
 </LinearLayout>

 

 

< 네비게이션 뷰 >

네비게이션 뷰 - 드로어 화면 구성

네비게이션 뷰는 토글을 눌러 열리는 슬라이드 형태의 메뉴입니다.

드로어 레이아웃 화면에서 위쪽은 아이콘과 문자열 등을 배치해고 아래쪽은 메뉴 항목을 나열하는 편입니다.

 

headerLayout은 윗부분에 해당되는 값이고, menu 부분은 아래 부분에 해당되는 값입니다.

<androidx.drawerlayout.widget.DrawerLayout
   <LinearLayout
   </LinearLayout>
   <com.google.android.material.navigation.NavigationView
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:gravity="center"
        android:fitsSystemWindows="true"
        android:id="@+id/mainDrawerView"
        app:headerLayout="@layout/navigation_header"
        app:menu="@menu/menu_navigation"/>
</androidx.drawerlayout.widget.DrawerLayout>

 

항목 선택 이벤트는 DrawerLayout의 setNavigationItemSelectedListner() 함수로 이벤트 핸들러 지정합니다.

binding.mainDrawerView.setNavigationItemSelectedListener{
   true
}

 

 

728x90