如何自定义TabLayout样式

AndroidTabLayout样式定制与选中效果实现

前言

在Android开发中经常会遇到tab页面,这样就需要tab+viewpager的方式来进行处理。谷歌官方提供了TabLayout,但是我们发现很多项目并不愿意使用,主要原因就是样式处理不够灵活。

当然TabLayout可以自己实现TabItem,这样就可以满足大部分需求。但是其实使用默认的TabItem也可以实现很多样式,我们可以使用一些巧妙的方法来达到我们需要的效果,比如:

WX20201209-185226@2x.png
下面我们就看如何一步步实现上面的效果

改变字体颜色、大小

这个很简单,xml中直接设置即可:

app:tabTextColor="@color/color_424243"
app:tabSelectedTextColor="@color/color_43a5f3"
android:textSize="16sp"

靠左显示

默认情况下所有item是等分显示的,想靠左显示,则需要设置

app:tabMode="scrollable"

这个设置其实是允许TabLayout滚动,这样就可以实现滚动效果的tab了

改变Indicator

首先改变它的颜色,很简单

app:tabIndicatorColor="@color/color_43a5f3"

但是默认Indicator是很长的,长度与Item一样长,很明显与我们的需求不一致。

其实这里还有一个设置,如下:

app:tabIndicatorFullWidth="false"

这个设置可以让Indicator不再与item一样长,但是它会保持与文字内容一样长。

但是很明显我们需求中它比内容要短很多,那怎么办?

这就需要我们自己设计一个drawable,先创建一个shape:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@color/color_43a5f3" />
    <corners android:radius="8dp" />

</shape>

这个我们都很熟悉,一个填充的圆角矩形。

但是不能直接使用,因为这样改变不了长度,我们需要使用layer-list留出间隙:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/bg_corner_8_43a5f3"
        android:height="3dp"
        android:left="15dp"
        android:right="15dp"/>
</layer-list>

这样这个drawable会在左右各留出15dp的空间,在中间填充圆角矩形。这里注意高度一定要设置,否则Indicator不显示,因为高度是0。

有人可能觉得直接在shape设置padding不一样么?

其实想一下就知道,padding并不能留白,只是让内容偏移,影响不是shape自己。所以要使用layer-list。

最后将这个layer-list设置为tab的Indicator即可:

app:tabIndicator="@drawable/tab_indicator_blue_short"

这里有一个小坑,仅仅设置tabIndicator不行,必须同时设置app:tabIndicatorColor,否则填充的是默认的颜色(绿色),也就是说shape中的颜色其实没有用到,只是用到了它的形状和框架。

这样其实就可以满足大部分Indicator的需求。最后整体代码如下:

<com.google.android.material.tabs.TabLayout
    android:id="@+id/indicator"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    app:tabTextColor="@color/color_424243"
    app:tabSelectedTextColor="@color/color_43a5f3"
    app:tabIndicatorFullWidth="false"
    app:tabMode="scrollable"
    app:tabIndicatorColor="@color/color_43a5f3"
    app:tabIndicator="@drawable/tab_indicator_blue_short"
    android:textSize="16sp"
    android:paddingLeft="10dp"/>

选中状态处理

最麻烦的就是这个选中处理,上图中可以看到需求要求选中时不仅仅改变颜色,字体也跟着变大,甚至加粗。

这个TabLayout没有暴露任何接口,通过源码也可以看到TabLayout根本没预留这种处理。那怎么办?

这也是很多人需要自定义TabItem或者完全自己实现tab的原因。其实我们可以通过一个巧妙的简单方法去实现。

TabLayout可以设置监听,如下:

tablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
            }
        });

在这里我们可以得到Tab对象,它并不是一个view,只是可以设置text,icon等,无法改变ui样式。但是它有一个属性:view,它是TabView类型的,继承Linearlayout。我们可以通过它做一些事情。

但是TabView是内部类,外部无法访问,所以通过view无法执行任何方法,很多同学立刻想到使用反射。确实反射可以实现,但是我尽力避免使用反射,主要还是兼容问题。我希望用更正式的方式来处理。

经过思考尝试,可以将view强转成View类型,因为即使官方代码大量改动,它依然一定是一个View。然后通过对其缩放来实现改变字体的大小。代码如下:

tablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                ((View)tab.view).setScaleX(1.1f);
                ((View)tab.view).setScaleY(1.1f);
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                ((View)tab.view).setScaleX(1.0f);
                ((View)tab.view).setScaleY(1.0f);
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                ((View)tab.view).setScaleX(1.1f);
                ((View)tab.view).setScaleY(1.1f);
            }
        });

为什么不直接改变字体大小?

这是因为view是LinearLayout,TextView是其中一个child,如果不通过反射就只能遍历childs获取TextView,这都不是我喜欢的方法。

缩放不会影响Indicator么?

这个不会影响,通过源码得知,TabView只包含icon和text,并不包含Indicator。而Indicator实际上是根据选中的item的位置及偏移动态绘制的,并不属于某个item,所以可以实现滑动的动画。

如果我们自己实现Tab,就需要计算这部分,还是有一定的工作量,所以不是特别复杂的效果还是建议使用官方的TabLayout。多研究研究就能得到需要的效果。

关注公众号:BennuCTech,发送“Android内核设计思想”获取《深入理解Android内核设计思想》电子书一份。

### 自定义TabLayout样式并在角标处添加红点通知标记 在安卓开发中,`TabLayout` 是一个非常常用的组件,用于显示分页标题。当需要在 `TabLayout` 的某个 Tab 标题上添加红点通知标记时,可以通过自定义 Tab 的布局来实现这一需求。 以下是具体实现方法: #### 1. 创建自定义 Tab 布局 首先,创建一个 XML 文件作为 Tab 的自定义布局。该布局可以包含一个 `TextView` 用于显示 Tab 标题,以及一个 `ImageView` 或 `View` 用于显示红点通知标记。 ```xml <!-- res/layout/custom_tab.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="center"> <TextView android:id="@+id/tab_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14sp" android:textColor="#000000" /> <View android:id="@+id/tab_notification_dot" android:layout_width="8dp" android:layout_height="8dp" android:background="@drawable/red_dot_background" android:visibility="gone" android:layout_marginTop="4dp" /> </LinearLayout> ``` 其中,`red_dot_background` 是一个圆形的 drawable 资源文件,用于定义红点的外观: ```xml <!-- res/drawable/red_dot_background.xml --> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="#FF0000" /> </shape> ``` #### 2. 设置自定义 Tab 视图 接下来,在代码中为每个 Tab 设置自定义视图,并根据需要显示或隐藏红点通知标记。 ```java // 初始化 TabLayout 和 ViewPager(如果使用) TabLayout tabLayout = findViewById(R.id.tab_layout); ViewPager viewPager = findViewById(R.id.view_pager); // 创建 Tab 并设置自定义视图 for (int i = 0; i < 2; i++) { TabLayout.Tab tab = tabLayout.newTab(); View customView = getLayoutInflater().inflate(R.layout.custom_tab, null); TextView tabTitle = customView.findViewById(R.id.tab_title); View notificationDot = customView.findViewById(R.id.tab_notification_dot); // 设置 Tab 标题 tabTitle.setText("Tab " + (i + 1)); // 根据条件显示或隐藏红点 if (i == 0) { // 假设第一个 Tab 需要显示红点 notificationDot.setVisibility(View.VISIBLE); } else { notificationDot.setVisibility(View.GONE); } tab.setCustomView(customView); tabLayout.addTab(tab); } // 添加 Tab 选中监听器 tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { View customView = tab.getCustomView(); if (customView != null) { TextView tabTitle = customView.findViewById(R.id.tab_title); tabTitle.setTextColor(Color.BLUE); // 修改选中状态的颜色 } } @Override public void onTabUnselected(TabLayout.Tab tab) { View customView = tab.getCustomView(); if (customView != null) { TextView tabTitle = customView.findViewById(R.id.tab_title); tabTitle.setTextColor(Color.BLACK); // 修改非选中状态的颜色 } } @Override public void onTabReselected(TabLayout.Tab tab) { // 处理重新选中的逻辑 } }); ``` #### 3. 注意事项 - 在自定义 Tab 布局后,无法直接调用 `setupWithViewPager` 方法绑定 `ViewPager`,需要手动为每个 Tab 设置视图[^2]。 - 红点的显示与隐藏逻辑可以根据实际需求动态调整,例如通过网络请求或本地数据变化触发更新[^1]。 #### 4. 效果展示 通过上述步骤,可以在 `TabLayout` 的每个 Tab 上添加自定义样式,并在特定位置显示红点通知标记。红点的显示和隐藏逻辑可以根据业务需求灵活调整。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BennuCTech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值