TabLayout 选中 item 加粗

举报
codexiaosheng 发表于 2022/02/28 16:18:17 2022/02/28
【摘要】 android TabLayout选项卡选择文字加粗显示,item间添加分割线

TabLayout 是谷歌官方推出的一款横向标签可滑动选择的控件,非常实用,几乎主流APP里面都能看到类似这样的功能,尤其是资讯类和视频类,随着官方的更新,这款控件也越来越好用了,支持的属性基本能满足日常需求。下面就记录一下扩展实现的一个功能和几个属性的小技巧。

示例功能说明

只有一个页面,页面中只有TabLayout ,TabLayout 的子itemxml 中添加,使用官方控件com.google.android.material.tabs.TabItem,我们的目的是要实现当 tab 切换时,对应选中的 tab 文字加粗,反之正常。

定义页面

首先需要在 app 下的 build.gradle 中添加如下依赖:

implementation 'com.google.android.material:material:1.3.0-alpha04'

这个引用是因为我的项目依赖库是基于 AndroidX 的,如果你是 support的,那么添加如下依赖:

implementation 'com.android.support:design:28.0.0'

接下来就可以写布局文件了,Activity 对应xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    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="48dp"
        android:overScrollMode="never"
        app:tabMode="scrollable"
        app:tabSelectedTextColor="@android:color/holo_red_light">

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Java" />

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Android" />

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="vue" />

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="flutter" />

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Kotlin" />
    </com.google.android.material.tabs.TabLayout>
</LinearLayout>

这里为了简单,就不与 ViewPager 结合演示了,其实并不影响,我们的重点工作是在 TabLayout 中。运行起来,如下图:

分析问题

很明显,我们看到这里具体满足我们的需求差了很大一截,有几个问题:

  • tab中的文字英文字母都大写了
  • tab对应的指示器线宽度不跟随文字长度
  • 切换的时候并不会加粗当前选中的tab

对于前两个问题解决起来并不难,通过TabLayout 属性就可以解决:

// 设置指示器线宽度跟随tab文字长度
app:tabIndicatorFullWidth="false"
// 避免默认英文字母大写
app:tabTextAppearance="@android:style/TextAppearance.Widget.TabWidget"

这样设置,前两个问题就解决了,看下图:

现在剩下最后一个问题了,也是本文的重点,需要我们在代码中实现。

选中tab文字加粗

这个其实一开始我的思路走错了,因为我的 tab 不是自定义的布局,而是通过接口获取数据动态显示的,并实现了与 ViewPager 的联动,初步想法是通过自定义Tab选中与否的样式来控制,实际操作发现不可行,最后看到一位博主提供的思路比较巧妙,是通过监听切换给tab设置 StyleSpan 来实现的,示例代码如下:

tabLayoutBinding.tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {

    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        if (tab == null || tab.getText() == null) {
            return;
        }

        String selectTab = tab.getText().toString().trim();

        SpannableString spannableString = new SpannableString(selectTab);
        StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);
        spannableString.setSpan(styleSpan, 0, selectTab.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

        tab.setText(spannableString);
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {
        if (tab == null || tab.getText() == null) {

            return;
        }

        String selectTab = tab.getText().toString().trim();

        SpannableString spannableString = new SpannableString(selectTab);
        StyleSpan styleSpan = new StyleSpan(Typeface.NORMAL);
        spannableString.setSpan(styleSpan, 0, selectTab.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

        tab.setText(spannableString);
    }

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

这样设置后,我们再看下效果:

当我们切换tab时,选中的tab文字就会加粗显示,但有一个问题,初次打开,默认选中的第一个tab不是加粗的,那么我们就在 onCreate() 方法中调用这个方法即可:

private void initFirstTab() {
    TabLayout.Tab tab = tabLayoutBinding.tabLayout.getTabAt(0);
    String selectTab = tab.getText().toString().trim();

    SpannableString spannableString = new SpannableString(selectTab);
    StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);
    spannableString.setSpan(styleSpan, 0, selectTab.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

    tab.setText(spannableString);
}

实际开发中请不要在这里直接调用,一定要确保你的tab item 数据是有的,之后再调用,避免空指针。

TabLayout 几个常用属性

  • tabRippleColor:默认会有一个选中的水波纹效果,如果不想要,将其设置为透明即可
  • tabIndicatorHeight:指示器线条的高度,如果不想要,设置为0即可

关于指示器的状态颜色,这里不做解释,自定义想要的xml即可。

给TabLayout item设置分割线

一般情况是不会有分割线的,但有些需求甚是奇怪,每个tab之间会有一个竖向的短线,大家应该能理解,实现起来也不难,看代码:

LinearLayout linearLayout = (LinearLayout) tabLayout.getChildAt(0);
linearLayout.setDividerPadding(30);
linearLayout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
linearLayout.setDividerDrawable(ContextCompat.getDrawable(this,R.drawable.layout_divider_vertical));

其中的线条就是xml定义的 layout_divider_vertical.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#ff0000"/>
    <size android:width="1dp"/>
</shape>

小结

本文介绍的常用属性和解决方案,其实很多时候会遇到,但总会忘记,这里记录一下,以方便后续开发,提高效率。

我是一名安卓开发工程师,最近正在学习Java后端知识,每天保持学习,掌握一项技能其实用不了多长时间,加油!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。