大家使用一些常见的 App 时都能发现 Tab 卡片切换效果,比如『AppGallery』『Mi Home』等:
这种交互将下方卡片和顶部 Tab 进行联动,用户可以通过左右滑动卡片,或者点击 Tab 切换卡片,特别适合将同一模组不同内容的页面合并展示。
得益于 Android 官方的良好封装,我们要实现这种方式也非常简单。
先来看布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
拆开两部分来看,顶部必然是使用 TabLayout
组件,下面则使用 ViewPager2
来实现。
既然有 ViewPager2
,那之前肯定有 ViewPager
,老版本的 ViewPager
是继承自 ViewGroup
自定义实现的,而 ViewPager2
虽然也继承自 ViewGroup
,但却是基于 RecyclerView
封装的,解决了 ViewPager
的大部分痛点,大多数情况下我们优先选择 ViewPager2
来实现我们的需求。
TabLayout
和 ViewPager2
都有自己的切换逻辑,那么我们需要做的,就是将它们关联起来,实现联动的效果。
class MainActivity : AppCompatActivity() {
private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
...
binding.viewPager.adapter = object : FragmentStateAdapter(this) {
override fun getItemCount() = 2
override fun createFragment(position: Int) = when (position) {
0 -> Fragment0()
else -> Fragment1()
}
}
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
when (position) {
0 -> tab.text = "Tab 0"
else -> tab.text = "Tab 1"
}
}.attach()
}
}
给 ViewPager2
设置一个 adapter
,并实现 FragmentStateAdapter
接口,重写 getItemCount()
和 createFragment()
方法,分别返回 ViewPager2
的页面数量和对应位置的 Fragment
。这部分属于 ViewPager2
的知识,这里不再赘述。
接下来,我们创建一个 TabLayoutMediator
对象,并调用它的 attach()
方法,将 TabLayout
和 ViewPager2
关联起来。同时还可以根据需要,对 TabLayout.Tab
做一些自定义的处理操作。
这样,我们就实现了 TabLayout
和 ViewPager2
联动。效果如下: