이번 글에서는 ViewPager2와 TabLayout을 사용하여 스와이프 가능한 탭 메뉴를 만들어보도록 하자.
XML파일 작성
먼저 viewpager와 tabLayout이 있는 메인 액티비티의 XML파일을 작성해주도록 하자.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"/>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/tab_layout"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
간단하게 viewpager와 tabLayout만 있는 XML을 작성해보았다.
Adapter
다음으로 viewpager에 연결할 adapter클래스를 새로 작성한다.
class ViewPagerAdapter(
private val fragmentList: ArrayList<Fragment>,
container: AppCompatActivity
): FragmentStateAdapter(container.supportFragmentManager, container.lifecycle) {
override fun getItemCount(): Int = fragmentList.count()
override fun createFragment(position: Int): Fragment = fragmentList[position]
}
화면에 표시할 fragment의 리스트와 container를 넣어주었고,
getItemCount는 하면에 표시할 페이지의 개수, createFragment는 각 페이지마다 보여줄 VIew를 반환해주도록 하면 된다.
위 코드에선 fragmentList를 parameter로 넣어주었기 때문에 각 위치의 fragment를 반환해주기만 하면 간단하다.
Fragments
위에서 만든 Adapter에 넣을 각 Fragment를 만들어주도록 하자.
class Fragment1: Fragment() {
private lateinit var binding: Fragment1Binding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = Fragment1Binding.inflate(inflater, container, false)
return binding.root
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/teal_200">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="1번"
android:textColor="@color/black"
android:textSize="50dp" />
</FrameLayout>
이 글에선 거창하게 만들 필요 없으니 위와 같이 간단한 fragment를 세 개 만들어주도록 하자.
ViewPager + TabLayout
이제 사전 준비가 다 끝났으니 마지막으로 viewpager와 tabLayout을 연결시키는 작업을 해주도록 하자.
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
initView()
}
private fun initView() {
val viewPager = binding.viewpager
val tabLayout = binding.tabLayout
val fragmentList = ArrayList<Fragment>()
fragmentList.add(Fragment1())
fragmentList.add(Fragment2())
fragmentList.add(Fragment3())
viewPager.adapter = ViewPagerAdapter(fragmentList, this)
val iconList = ArrayList<Drawable?>()
iconList.add(ContextCompat.getDrawable(this, R.drawable.ic_launcher_foreground))
iconList.add(ContextCompat.getDrawable(this, R.drawable.ic_launcher_foreground))
iconList.add(ContextCompat.getDrawable(this, R.drawable.ic_launcher_foreground))
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = "${position}번"
tab.icon = iconList[position]
}.attach()
}
}
코드에서처럼 TabLayoutMediator에 tabLayout과 viewPager를 argument로 주어서 둘을 연결시킬 수 있다.
이때 각 탭의 텍스트와 아이콘 등을 설정해줄 수 있다.
순환 페이지 (Circular ViewPager)
위와 같이 만들었을 땐 1번에서 왼쪽으로 스와이프해서 3번으로 가거나
3번에서 오른쪽으로 스와이프해서 1번으로 가는 동작이 불가능하다.
이런 동작이 가능하도록 하려면 아래 코드를 위 코드 아래에 추가해주면 된다.
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
var currentPosition = 0
var currentState = 0
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {
if (currentState == ViewPager2.SCROLL_STATE_DRAGGING && currentPosition == position) {
when (currentPosition) {
0 -> viewPager.currentItem = fragmentList.lastIndex
fragmentList.lastIndex -> viewPager.currentItem = 0
}
}
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
}
override fun onPageSelected(position: Int) {
currentPosition = position
super.onPageSelected(position)
}
override fun onPageScrollStateChanged(state: Int) {
currentState = state
super.onPageScrollStateChanged(state)
}
})
Select Tab
마지막으로 화면 시작할 때 시작 탭을 지정해주고 싶은 경우가 있다.
이런 때 코드에서 해당 tab을 선택해주면 되는데, 아래와 같이 선택할 수 있다.
tabLayout.getTabAt(1)?.select()
이때 문제는 이 방법을 사용하면 tabLayout의 select indicator가 사라진다는 점이다.
때문에 탭을 선택할 때에는 아래와 같이 viewPager를 통해서 지정해주면 된다.
viewPager.setCurrentItem(1, false)
이때 두 번째 argument인 smoothScroll을 true로 줄경우 위의 tabLayout때와 같이 indicator가 사라지기 때문에 주의하자.
'안드로이드 > 개발관련(Kotlin)' 카테고리의 다른 글
안드로이드 Circle Progress (로딩 애니메이션) 만들기 (0) | 2023.03.30 |
---|---|
안드로이드 뒤로 가기 두 번 눌러서 종료 (onBackPressed, onBackPressedDispater) (0) | 2023.03.29 |
안드로이드 No matching variant of com.android.tools.build:gradle:* was found 오류 해결법 (0) | 2023.03.28 |
retrofit을 사용한 안드로이드와 Node.js간 통신 (0) | 2023.02.28 |
안드로이드 타이틀바 없애는법 (0) | 2023.02.28 |