TabLayout 是 Android 中用于创建标签式导航的组件,通常和 ViewPager 一起使用来实现可滑动的视图切换。它提供了一个简单的 UI 控件,允许用户通过点击标签或滑动来切换视图。
在 Kotlin 中,TabLayout 的使用方式通常如下:
1. 添加依赖
在 build.gradle 文件中添加 TabLayout 和 ViewPager2 的依赖(ViewPager2 是新版的 ViewPager,推荐使用):
dependencies {
implementation "com.google.android.material:material:1.5.0"
implementation "androidx.viewpager2:viewpager2:1.0.0"
}
1.1 常用属性
<com.google.android.material.tabs.TabLayout
android:id="@+id/tlyTab"
android:layout_width="0dp"
android:layout_height="35dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:textAlignment="center"
app:tabBackground="@android:color/transparent"
app:tabIndicator="@color/common_transparent"
app:tabIndicatorColor="@color/common_transparent"
app:tabIndicatorFullWidth="false"
app:tabIndicatorHeight="8dp"
app:tabMinWidth="0dp"
app:tabMode="scrollable"
app:tabPaddingBottom="0dp"
app:tabPaddingEnd="6dp"
app:tabPaddingStart="6dp"
app:tabPaddingTop="0dp"
app:tabRippleColor="@null"
app:tabSelectedTextColor="#000000"
app:tabTextAppearance="@style/TabTextLayoutTopTab"
app:tabTextColor="#8E8A99" />
这段代码是 TabLayout 的布局定义,其中有许多自定义属性。下面是各个属性的解释:
@1. android:layout_width="0dp"
• 作用:定义 TabLayout 的宽度。设置为 0dp 是为了和父容器的 layout_weight 配合使用,通过 layout_weight 来分配宽度。
@2. android:layout_height="35dp"
• 作用:定义 TabLayout 的高度为 35dp。
@3. android:layout_weight="1"
• 作用:当 TabLayout 位于 LinearLayout 中时,layout_weight 可以控制该组件所占用的剩余空间的比例。1 表示它会占据剩余空间的 1 倍。
@4. android:background="@android:color/transparent"
• 作用:设置 TabLayout 的背景为透明色。
@5. android:textAlignment="center"
• 作用:设置 TabLayout 中的文本对齐方式为居中。
@6. app:tabBackground="@android:color/transparent"
• 作用:设置每个 tab 项的背景为透明。此属性可用于自定义 tab 的背景。
@7. app:tabIndicator="@color/common_transparent"
• 作用:设置 tab 指示器(通常是下划线)的背景颜色。在此处设置为透明,意味着 tab 下方没有可见的指示器。
@8. app:tabIndicatorColor="@color/common_transparent"
• 作用:设置 tab 指示器的颜色。在此例中,设置为透明色,指示器将不可见。
@9. app:tabIndicatorFullWidth="false"
• 作用:如果设置为 true,指示器会扩展到整个 tab 的宽度;如果设置为 false,指示器的宽度将仅与文本宽度匹配。
@10. app:tabIndicatorHeight="8dp"
• 作用:设置指示器的高度为 8dp。通常情况下,这个指示器是 tab 下方的横线,用于标识当前选中的 tab。
@11. app:tabMinWidth="0dp"
• 作用:设置 tab 最小宽度。0dp 表示 tab 宽度不会有最小限制,它将根据内容大小来调整宽度。
@12. app:tabMode="scrollable"
• 作用:设置 TabLayout 的模式为 scrollable,意味着当 tab 项过多时,tab 会变得可滑动。如果不设置为 scrollable,tab 会在一行显示不下时缩小尺寸。
@13. app:tabPaddingBottom="0dp"
• 作用:设置 tab 项底部的内边距为 0dp,也就是没有额外的空间。
@14. app:tabPaddingEnd="6dp"
• 作用:设置 tab 项右侧的内边距为 6dp。
@15. app:tabPaddingStart="6dp"
• 作用:设置 tab 项左侧的内边距为 6dp。
@16. app:tabPaddingTop="0dp"
• 作用:设置 tab 项顶部的内边距为 0dp。
@17. app:tabRippleColor="@null"
• 作用:设置 tab 的点击波纹效果。@null 表示禁用点击时的波纹效果。
@18. app:tabSelectedTextColor="#000000"
• 作用:设置选中 tab 时,文本的颜色为黑色 (#000000)。
@19. app:tabTextAppearance="@style/TabTextLayoutTopTab"
• 作用:应用自定义的文本样式,TabTextLayoutTopTab 是你自定义的样式,里面包含了 tab 文本的字体大小、颜色等属性。
@20. app:tabTextColor="#8E8A99"
• 作用:设置未选中时,tab 文本的颜色为 #8E8A99(一种灰色调)。
2. 布局文件
你需要在布局文件中添加 TabLayout 和 ViewPager2。
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- TabLayout -->
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="@android:color/holo_blue_light"
app:tabSelectedTextColor="@android:color/holo_blue_light"
app:tabTextColor="@android:color/darker_gray"/>
<!-- ViewPager2 -->
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/tabLayout"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
3. 设置适配器和连接 TabLayout 和 ViewPager2
在你的 Activity 或 Fragment 中,设置 ViewPager2 的适配器,并将它和 TabLayout 进行绑定。
class MainActivity : AppCompatActivity() {
private lateinit var tabLayout: TabLayout
private lateinit var viewPager: ViewPager2
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tabLayout = findViewById(R.id.tabLayout)
viewPager = findViewById(R.id.viewPager)
val adapter = ViewPagerAdapter(this)
viewPager.adapter = adapter
// Connect the TabLayout with ViewPager
TabLayoutMediator(mBinding.tlyTab, viewPager2) { tab, position ->
tab.customView = AppCompatTextView(mContext).apply {
text = list[position]
textSize = 15f
maxLines = 1
typeface = resources.getFont(com.smile.common.R.font.sans_pro_black)
if (skinConfigBean.isOpen) {
setTextColor(Color.parseColor(skinConfigBean.titleColor))
} else {
setTextColor(Color.parseColor("#8E8A99"))
}
}
}.attach()
}
}
4. 创建适配器
ViewPagerAdapter 是一个继承自 FragmentStateAdapter 的适配器,用来管理每个 tab 页面显示的内容。
class ViewPagerAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {
override fun getItemCount(): Int {
return 3 // Number of tabs
}
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> Fragment1()
1 -> Fragment2()
2 -> Fragment3()
else -> Fragment1()
}
}
}
5. 创建各个 Fragment
你可以为每个 tab 页面创建对应的 Fragment,比如:
class Fragment1 : Fragment(R.layout.fragment_1) {
// Your code for fragment 1
}
class Fragment2 : Fragment(R.layout.fragment_2) {
// Your code for fragment 2
}
class Fragment3 : Fragment(R.layout.fragment_3) {
// Your code for fragment 3
}
6.动态设置tab的文字大小和颜色
val tabCount = mBinding.tlyTab.tabCount
for (i in 0 until tabCount) {
val tab = mBinding.tlyTab.getTabAt(i)
if (tab != null) {
// 根据 tab 的位置来判断是否选中
val isSelected = i == mBinding.vpPager.currentItem
updateTabSelect(skinConfigBean, i, isSelected)
}
}
//设置tablayout底部图标
initTabBottomDrawable(skinConfigBean)
/**
* description:初始化tablayout底部图标(底部图标如果是从网路下载,会被拉伸,用这个方式进行实现)
*/
private fun initTabBottomDrawable(skinConfigBean: SkinConfigBean) {
// 设置tablayout底部图标初始位置
mBinding.tlyTab.postDelayed({
// 获取当前选中的tab
val selectedTab: TabLayout.Tab? = mBinding.tlyTab.getTabAt(1)
if (selectedTab?.customView != null) {
// 获取tab的宽度和位置
val tabWidth = selectedTab.customView!!.width.toFloat()
val location = IntArray(2)
selectedTab.getCustomView()!!.getLocationOnScreen(location)
val targetXFixed = location[0]
// 设置黄色按钮初始位置(在tab底部正中间)
val initialX: Float = targetXFixed + (tabWidth - mBinding.ivFragmentTab.getWidth()) / 2
mBinding.ivFragmentTab.setX(initialX)
mBinding.ivFragmentTab.setY(location[1].toFloat() + UiUtil.dp2Px(22 - 4, mContext))
}
}, 50)
//设置tablayout底部图标
if (skinConfigBean.isOpen) {
skinConfigBean.titleBottom?.let {
SkinManager.setViewBackgroundDrawable(mContext, mBinding.ivFragmentTab, skinConfigBean.titleBottom)
} ?: run {
mBinding.ivFragmentTab.setBackgroundResource(R.drawable.iv_indicator_tab_square_new)
}
} else {
mBinding.ivFragmentTab.setBackgroundResource(R.drawable.iv_indicator_tab_square_new)
}
}
//在tab切换的时候,动态设置bottomDrawable的位置
override fun onSelect(position: Int) {
updateTabSelect(mSkinConfigBeanDefault, position, true)
mBinding.tlyTab.postDelayed({ // 获取选中tab的位置
val selectedTab: TabLayout.Tab? = mBinding.tlyTab.getTabAt(position)
if (selectedTab?.customView != null) {
val location = IntArray(2)
selectedTab.getCustomView()!!.getLocationOnScreen(location)
val targetXFixed = location[0]
// 获取tab的宽度
val tabWidth: Float = selectedTab.getCustomView()!!.getWidth().toFloat()
// 计算按钮中心点位置,确保黄色按钮在选中tab的底部正中间
val targetCenterX: Float = targetXFixed + (tabWidth - mBinding.ivFragmentTab.getWidth()) / 2
// 创建平移动画
val animator = ObjectAnimator.ofFloat(mBinding.ivFragmentTab, "translationX", mBinding.ivFragmentTab.getX(), targetCenterX)
animator.setDuration(300) // 设置动画时间
animator.start()
}
}, 50)
}
这样就完成了一个基本的 TabLayout 和 ViewPager2 的集成,允许用户通过点击 Tab 或滑动来切换不同的内容页面。