Material Design 是 Google 推出的一种设计语言,旨在提供一种更加自然、直观和一致的用户体验。其中,TabLayout 是一种常见的 UI 组件,用于切换不同的标签页。在本文中,我们将介绍如何自定义 TabLayout,以满足不同的设计需求。
TabLayout 简介
TabLayout 是 Android Material Design 库中的一种 UI 组件,用于显示多个标签页。TabLayout 可以和 ViewPager 配合使用,实现滑动切换标签页的效果。TabLayout 的主要特点包括:
- 支持图标和文本混合展示;
- 支持滑动切换标签页;
- 支持自定义样式和布局。
在使用 TabLayout 时,我们通常需要设置一些属性,例如:
// www.javascriptcn.com code example
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="center"
app:tabIndicatorColor="@color/colorAccent"
app:tabSelectedTextColor="@color/colorAccent"
app:tabTextColor="@color/colorPrimary" />其中,tabMode 和 tabGravity 分别用于设置 TabLayout 的模式和对齐方式。tabIndicatorColor、tabSelectedTextColor 和 tabTextColor 则分别用于设置指示器颜色、选中文本颜色和未选中文本颜色。
自定义 TabLayout
除了上述基本属性,我们还可以通过自定义 TabLayout,实现更加个性化的效果。在自定义 TabLayout 时,我们可以重写 TabLayout.TabView 类,实现自己的布局和样式。
自定义布局
首先,我们可以通过重写 TabLayout.TabView 类,实现自定义布局。具体步骤如下:
- 创建一个继承自
TabLayout.TabView的类,例如CustomTabView。
class CustomTabView(context: Context) : TabLayout.TabView(context) {
// ...
}- 在
CustomTabView中重写onCreateDrawableState方法,返回自定义布局的资源 ID。
override fun onCreateDrawableState(extraSpace: Int): IntArray {
val drawableState = super.onCreateDrawableState(extraSpace + 1)
mergeDrawableStates(drawableState, intArrayOf(R.attr.state_custom))
return drawableState
}其中,R.attr.state_custom 是自定义的属性,用于标识自定义布局。
- 在布局文件中,定义自定义布局的 XML 文件,例如
custom_tab_view.xml。
// www.javascriptcn.com code example
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/tab_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/tab_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tab Title" />
</LinearLayout>其中,tab_icon 和 tab_title 分别用于显示图标和文本。
- 在
CustomTabView中,使用LayoutInflater加载自定义布局,并设置图标和文本。
val view = LayoutInflater.from(context).inflate(R.layout.custom_tab_view, this, false) val icon = view.findViewById<ImageView>(R.id.tab_icon) val title = view.findViewById<TextView>(R.id.tab_title) icon.setImageResource(tab.iconResId) title.text = tab.text addView(view)
其中,tab.iconResId 和 tab.text 分别表示当前标签页的图标和文本。
- 在 TabLayout 中,设置自定义 TabView 类型。
tabLayout.tabMode = TabLayout.MODE_SCROLLABLE tabLayout.addTab(tabLayout.newTab().setCustomView(CustomTabView(this)))
其中,tabMode 必须设置为 MODE_SCROLLABLE,才能支持自定义布局。
自定义样式
除了自定义布局,我们还可以通过自定义样式,实现更加个性化的效果。在自定义样式时,我们可以重写 TabLayout 的样式,并设置自定义属性。
- 在
styles.xml中,定义自定义样式。
<style name="CustomTabLayout" parent="Widget.Design.TabLayout">
<item name="tabIndicatorColor">@color/colorAccent</item>
<item name="tabSelectedTextColor">@color/colorAccent</item>
<item name="tabTextColor">@color/colorPrimary</item>
<item name="tabBackground">@drawable/custom_tab_background</item>
</style>其中,tabBackground 是自定义属性,用于设置标签页的背景。
- 在
drawable文件夹中,创建custom_tab_background.xml文件,定义自定义背景样式。
// www.javascriptcn.com code example
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="@color/colorAccent" />
<corners android:radius="16dp" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@android:color/transparent" />
</shape>
</item>
</selector>其中,state_selected 表示标签页是否选中。当标签页选中时,使用圆角矩形背景,并设置背景色为 colorAccent;否则,使用透明背景。
- 在 TabLayout 中,设置自定义样式。
tabLayout.tabMode = TabLayout.MODE_SCROLLABLE tabLayout.tabTextColors = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.colorPrimary)) tabLayout.setSelectedTabIndicatorColor(ContextCompat.getColor(this, R.color.colorAccent)) tabLayout.setBackgroundResource(R.drawable.custom_tab_background) tabLayout.tabRippleColor = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.colorAccent))
其中,tabTextColors 和 setSelectedTabIndicatorColor 分别用于设置文本颜色和指示器颜色。setBackgroundResource 用于设置背景样式。tabRippleColor 用于设置水波纹效果颜色。
示例代码
最终,我们将自定义布局和自定义样式结合起来,实现一个自定义 TabLayout 的示例。完整代码如下:
// www.javascriptcn.com code example
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val tabLayout = findViewById<TabLayout>(R.id.tab_layout)
tabLayout.tabMode = TabLayout.MODE_SCROLLABLE
tabLayout.tabTextColors = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.colorPrimary))
tabLayout.setSelectedTabIndicatorColor(ContextCompat.getColor(this, R.color.colorAccent))
tabLayout.setBackgroundResource(R.drawable.custom_tab_background)
tabLayout.tabRippleColor = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.colorAccent))
for (i in 1..5) {
val tab = tabLayout.newTab()
tab.icon = ContextCompat.getDrawable(this, R.drawable.ic_launcher)
tab.text = "Tab $i"
tabLayout.addTab(tab.setCustomView(CustomTabView(this)))
}
}
class CustomTabView(context: Context) : TabLayout.TabView(context) {
init {
LayoutInflater.from(context).inflate(R.layout.custom_tab_view, this, true)
}
override fun onCreateDrawableState(extraSpace: Int): IntArray {
val drawableState = super.onCreateDrawableState(extraSpace + 1)
mergeDrawableStates(drawableState, intArrayOf(R.attr.state_custom))
return drawableState
}
override fun setSelected(selected: Boolean) {
super.setSelected(selected)
val icon = findViewById<ImageView>(R.id.tab_icon)
val title = findViewById<TextView>(R.id.tab_title)
if (selected) {
icon.setColorFilter(ContextCompat.getColor(context, R.color.colorAccent), PorterDuff.Mode.SRC_IN)
title.setTextColor(ContextCompat.getColor(context, R.color.colorAccent))
} else {
icon.setColorFilter(ContextCompat.getColor(context, R.color.colorPrimary), PorterDuff.Mode.SRC_IN)
title.setTextColor(ContextCompat.getColor(context, R.color.colorPrimary))
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = MeasureSpec.getSize(heightMeasureSpec)
setMeasuredDimension(width, height + 16.dpToPx(context))
}
private fun Int.dpToPx(context: Context): Int {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics).toInt()
}
}
}其中,activity_main.xml 文件如下:
// www.javascriptcn.com code example
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="center" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>custom_tab_view.xml 文件如下:
// www.javascriptcn.com code example
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/tab_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/tab_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tab Title" />
</LinearLayout>custom_tab_background.xml 文件如下:
// www.javascriptcn.com code example
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="@color/colorAccent" />
<corners android:radius="16dp" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@android:color/transparent" />
</shape>
</item>
</selector>结语
本文介绍了如何自定义 TabLayout,包括自定义布局和自定义样式。通过自定义 TabLayout,我们可以实现更加个性化的效果,提升用户体验。同时,本文也提供了示例代码,方便读者实践和参考。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d18dcfa941bf71343415f7