前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android原生TabLayout使用全解析,看这篇就够了

Android原生TabLayout使用全解析,看这篇就够了

作者头像
yechaoa
发布于 2022-06-10 06:57:09
发布于 2022-06-10 06:57:09
10.4K00
代码可运行
举报
文章被收录于专栏:移动开发专栏移动开发专栏
运行总次数:0
代码可运行

前言

为什么会有这篇文章呢,是因为之前关于TabLayout的使用陆陆续续也写了好几篇了,感觉比较分散,且不成体系,写这篇文章的目的就是希望能把各种效果的实现一次性讲齐,所以也有了标题的「看这篇就够了」。

TabLayout作为导航组件来说,使用场景非常的多,也意味着要满足各种各样的需求。

在效果实现上,有同学会选择自定义View来做,定制性高,但易用性、稳定性、维护性不敢保证,使用官方组件能避免这些不确定性,一是开源,有很多大佬共建,会不停的迭代;二是经过大型app验证,比如google play;有了这两点,基本可以放心大胆的使用官方组件了。

那可能有的同学又会说,道理我都懂,可是不满足需求啊,只能自定义了。是的,早期的api确实不够丰富,在某些需求的实现上显得捉襟见肘,但是google也在不断的迭代,目前为止,常见的样式都能满足。

效果图

简介

  • TabLayout:一个横向可滑动的菜单导航ui组件
  • Tab:TabLayout中的item,可以通过newTab()创建
  • TabView:Tab的实例,是一个包含ImageView和TextView的线性布局
  • TabItem:一种特殊的“视图”,在TabLayout中可以显式声明Tab

官方文档

功能拆解

Material Design 组件最新正式版依赖:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
implementation 'com.google.android.material:material:1.5.0'

1.基础实现

1.1 xml动态写法
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tab_layout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        app:tabIndicatorColor="@color/colorPrimary"
        app:tabMaxWidth="200dp"
        app:tabMinWidth="100dp"
        app:tabMode="fixed"
        app:tabSelectedTextColor="@color/colorPrimary"
        app:tabTextColor="@color/gray" />

只写一个Layout,item可以配合ViewPager来生成。

1.2 xml静态写法
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 <com.google.android.material.tabs.TabLayout
         android:layout_height="wrap_content"
         android:layout_width="match_parent">

     <com.google.android.material.tabs.TabItem
             android:text="@string/tab_text"/>

     <com.google.android.material.tabs.TabItem
             android:icon="@drawable/ic_android"/>

 </com.google.android.material.tabs.TabLayout>

属于固定写法,比如我们非常确定item有几个,可以通过TabItem显式声明。

1.3 kotlin/java代码写法
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    val tab = mBinding.tabLayout7.newTab()
    tab.text = it.key
    //...
    mBinding.tabLayout7.addTab(tab)

这种情况适合Tab的数据是动态的,比如接口数据回来之后,再创建Tab并添加到TabLayout中。

2.添加图标

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mBinding.tabLayout2.getTabAt(index)?.setIcon(R.mipmap.ic_launcher)

获取Tab然后设置icon。

Tab内部其实是一个TextViewImageView,添加图标就是给ImageView设置icon。

3.字体大小、加粗

通过app:tabTextAppearance给TabLayout设置文本样式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <com.google.android.material.tabs.TabLayout
		...
        app:tabTextAppearance="@style/MyTabLayout"
		/>

style:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <style name="MyTabLayout">
        <item name="android:textSize">20sp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textAllCaps">false</item>
    </style>

比如这里设置了字体大小和加粗。

默认字体大小14sp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dimen name="design_tab_text_size">14sp</dimen>

4.去掉Tab长按提示文字

长按Tab时会有一个提示文字,类似Toast一样。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * 隐藏长按显示文本
     */
    private fun hideToolTipText(tab: TabLayout.Tab) {
        // 取消长按事件
        tab.view.isLongClickable = false
        // api 26 以上 设置空text
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
            tab.view.tooltipText = ""
        }
    }

可以取消长按事件,在api26以上也可以设置提示文本为空。

5.去掉下划线indicator

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
app:tabIndicatorHeight="0dp"

设置高度为0即可。

注意,单纯设置tabIndicatorColor为透明,其实不准确,默认还是有2dp的,根本瞒不过射鸡师的眼睛。

6.下划线的样式

通过app:tabIndicator可以设置自定义的样式,比如通过shape设置圆角和宽度。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <com.google.android.material.tabs.TabLayout
        ...
        app:tabIndicator="@drawable/shape_tab_indicator"
        app:tabIndicatorColor="@color/colorPrimary"
		/>

注意:Indicator的颜色在shape中设置是无效的,需要通过app:tabIndicatorColor设置才可以

shape:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:width="15dp"
        android:height="5dp"
        android:gravity="center">
        <shape>
            <corners android:radius="5dp" />
            <!--color无效,源码用tabIndicatorColor-->
            <solid android:color="@color/colorPrimary" />
        </shape>
    </item>
</layer-list>

7.下划线的宽度

默认情况下,tabIndicator的宽度是填充整个Tab的,比如上图中的第一个,我们可以简单的设置不填充,与文本对齐,即第二个效果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
app:tabIndicatorFullWidth="false"

也可以像上一节那样,通过shape自定义tabIndicator的宽度。

8.Tab分割线

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  /** A {@link LinearLayout} containing {@link Tab} instances for use with {@link TabLayout}. */
  public final class TabView extends LinearLayout {
  
  }

通过源码可以看到内部实现TabView继承至LinearLayout,我们知道LinearLayout是可以给子view设置分割线的,那我们就可以通过遍历来添加分割线

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        //设置 分割线
        for (index in 0..mBinding.tabLayout4.tabCount) {
            val linearLayout = mBinding.tabLayout4.getChildAt(index) as? LinearLayout
            linearLayout?.let {
                it.showDividers = LinearLayout.SHOW_DIVIDER_MIDDLE
                it.dividerDrawable = ContextCompat.getDrawable(this, R.drawable.shape_tab_divider)
                it.dividerPadding = 30
            }
        }

shape_tab_divider:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/colorPrimary" />
    <size android:width="1dp" android:height="10dp" />
</shape>

9.TabLayout样式

上图中的效果其实是TabLayout样式+tabIndicator样式形成的一个「整体」的效果。

TabLayout是两边半圆的一个长条,这个我们通过编写shape设置给其背景即可实现。

shape_tab_bg:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="999dp" />
    <solid android:color="@color/colorPrimary" />
</shape>

这个效果的关键在于tabIndicator的高度与TabLayout的高度相同,所以二者高度设置一致即可。

shape_full_tab_indicator:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:gravity="center" android:top="0.5dp" android:bottom="0.5dp">
        <shape>
            <!-- 上下边距合计1dp 高度减少1dp -->
            <size android:height="41dp" />
            <corners android:radius="999dp" />
            <solid android:color="@color/white" />
        </shape>
    </item>
</layer-list>

TabLayout:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tab_layout6"
        android:layout_width="wrap_content"
        android:layout_height="42dp"
        android:layout_gravity="center"
        android:layout_marginTop="10dp"
        android:background="@drawable/shape_tab_bg"
        app:tabIndicator="@drawable/shape_full_tab_indicator"
        app:tabIndicatorColor="@color/white"
        app:tabIndicatorFullWidth="true"
        app:tabIndicatorHeight="42dp"
        app:tabMinWidth="96dp"
        app:tabMode="fixed"
        app:tabSelectedTextColor="@color/colorPrimary"
        app:tabTextColor="@color/black" />

10.Tab添加小红点

添加小红点的功能还是比较常见的,好在TabLayout也提供了这种能力,其实添加起来也非常简单,难在未知。

可以设置带数字的红点,也可以设置没有数字单纯的一个点。

通过getOrCreateBadge可以对红点进行简单的配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        // 数字
        mBinding.tabLayout5.getTabAt(defaultIndex)?.let { tab ->
            tab.orCreateBadge.apply {
                backgroundColor = Color.RED
                maxCharacterCount = 3
                number = 99999
                badgeTextColor = Color.WHITE
            }
        }

        // 红点
        mBinding.tabLayout5.getTabAt(1)?.let { tab ->
            tab.orCreateBadge.backgroundColor = ContextCompat.getColor(this, R.color.orange)
        }

getOrCreateBadge实际上是获取或创建BadgeDrawable

通过源码发现,BadgeDrawable除了TabLayout引用之外,还有NavigationBarItemView、NavigationBarMenuView、NavigationBarView,意味着它们也同样具备着小红点这种能力。其实别的view也是可以具备的。

关于小红点这里就不展开了,非常推荐查看我之前写的这篇:【涨姿势】你没用过的BadgeDrawable

Author:yechaoa

11.获取隐藏的Tab

上一节中我们实现了小红点效果,那如果一屏显示不够的情况下,如何提示未展示的信息呢,比如上面我们如何把未显示的tab且有数字的Tab提示出来呢?常见的解决方案都是在尾部加一个红点提示。

那么问题来了,如何判断某一个Tab是否可见呢,翻看了源码,可惜并没有提供相应的api,那只能我们自己实现了。

我们前面添加小红点是根据Tab添加的,Tab内部实现也是一个view,那view就可以判断其是否可见。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    private fun isShowDot(): Boolean {
        var showIndex = 0
        var tipCount = 0
        companyMap.keys.forEachIndexed { index, _ ->
            mBinding.tabLayout7.getTabAt(index)?.let { tab ->
                val tabView = tab.view as LinearLayout
                val rect = Rect()
                val visible = tabView.getLocalVisibleRect(rect)
                // 可见范围小于80%也在计算范围之内,剩下20%宽度足够红点透出(可自定义)
                if (visible && rect.right > tab.view.width * 0.8) {
                    showIndex = index
                } else {
                    //if (index > showIndex) // 任意一个有count的tab隐藏就会显示,比如第一个在滑动过程中会隐藏,也在计算范围之内
                    if (index > lastShowIndex) { // 只检测右侧隐藏且有count的tab 才在计算范围之内
                        tab.badge?.let { tipCount += it.number }
                    }
                }

            }
        }
        lastShowIndex = showIndex
        return tipCount > 0
    }

上面的方法中就是判断是否需要显示右侧提示的小红点。

计算规则:Tab不可见,且Tab上的红点数字大于0的即在计算范围之内。

这里有一个优化的点,比如上图中的“腾讯”Tab,它是可见的,但是红点不可见,那么问题就来了,如果我们没有提示到,是很容易产生客诉的,所以这里在计算的时候也加了一个条件,就是可见范围小于80%也在计算范围之内,剩下20%的宽度是足够Tab上的红点透出的(也可自定义)。

同时在TabLayout滑动的过程中也应该加上判断显示的逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        // mBinding.tabLayout7.setOnScrollChangeListener() // min api 23 (6.0)
        // 适配 5.0  滑动过程中判断右侧小红点是否需要显示
        mBinding.tabLayout7.viewTreeObserver.addOnScrollChangedListener {
            mBinding.vArrowDot.visibility = if (isShowDot()) View.VISIBLE else View.INVISIBLE
        }

还有初始化时的判断逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    override fun onResume() {
        super.onResume()
        // 初始化判断右侧小红点是否需要显示
        mBinding.tabLayout7.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                mBinding.vArrowDot.visibility = if (isShowDot()) View.VISIBLE else View.INVISIBLE
                mBinding.tabLayout7.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        })
    }

12.Tab宽度自适应

细心的同学会发现,这个TabLayout的item左右间距都是一样的,不管标题是两个字还是四个字的,左右间距都是相等的,而实际上的效果是两个字的Tab要比四个字的Tab左右间距要大一些的,那这个效果是怎么实现的呢?

实际上是我们设置了tabMinWidth

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
app:tabMinWidth="50dp"

源码中默认的是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  private int getTabMinWidth() {
    if (requestedTabMinWidth != INVALID_WIDTH) {
      // If we have been given a min width, use it
      return requestedTabMinWidth;
    }
    // Else, we'll use the default value
    return (mode == MODE_SCROLLABLE || mode == MODE_AUTO) ? scrollableTabMinWidth : 0;
  }
  1. requestedTabMinWidth是根据xml设置获取的。
  2. 假如xml没设置tabMinWidth的情况下,且tabMode是scrollable的情况下,会返回默认配置,否则为0,即tabMode为fixed的情况。

系统默认配置scrollableTabMinWidth:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dimen name="design_tab_scrollable_min_width">72dp</dimen>

在两个字和四个字的标题都存在的情况下,两个字用这个默认宽度就会有多余的间距,所以会出现间距不均等的情况,通过设置覆盖默认即可解决。

13.自定义Item View

前面讲到Tab内部实现是一个View,那我们就可以通过官方提供api(setCustomView)来自定义这个view。

setCustomView的两种方式:

  • public Tab setCustomView(@Nullable View view)
  • public Tab setCustomView(@LayoutRes int resId)

我们先编写一个自定义的布局文件,布局文件比较简单,一个LottieAnimationView和TextView。

再通过Tab添加进去即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        val animMap = mapOf("party" to R.raw.anim_confetti, "pizza" to R.raw.anim_pizza, "apple" to R.raw.anim_apple)

        animMap.keys.forEach { s ->
            val tab = mBinding.tabLayout8.newTab()
            val view = LayoutInflater.from(this).inflate(R.layout.item_tab, null)
            val imageView = view.findViewById<LottieAnimationView>(R.id.lav_tab_img)
            val textView = view.findViewById<TextView>(R.id.tv_tab_text)
            imageView.setAnimation(animMap[s]!!)
            imageView.setColorFilter(Color.BLUE)
            textView.text = s
            tab.customView = view
            mBinding.tabLayout8.addTab(tab)
        }

14.使用Lottie

Lottie是一个可以在多平台展示动画的库,相信很多同学都已经用过了,就不详细展开了,感兴趣的可以查看Lottie官方文档

Lottie依赖:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
implementation "com.airbnb.android:lottie:5.0.1"

上一节中我们实现了自定义TabLayout的Item View,在这个自定义的布局中,我们用LottieAnimationView来承载动画的展示。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/item_tab"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical">

    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lav_tab_img"
        android:layout_width="30dp"
        android:layout_height="30dp"
        app:lottie_colorFilter="@color/black"
        app:lottie_rawRes="@raw/anim_confetti" />

    <TextView
        android:id="@+id/tv_tab_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        android:textColor="@color/black"
        android:textSize="14sp" />

</androidx.appcompat.widget.LinearLayoutCompat>

添加的方式也在上一节中讲过了,我们只需要控制好选中、未选中的状态即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        mBinding.tabLayout8.addOnTabSelectedListener(object : OnTabSelectedListener {
            override fun onTabSelected(tab: TabLayout.Tab?) {
                tab?.setSelected()
                tab?.let { mBinding.viewPager.currentItem = it.position }
            }

            override fun onTabUnselected(tab: TabLayout.Tab?) {
                tab?.setUnselected()
            }

            override fun onTabReselected(tab: TabLayout.Tab?) {

            }
        })

这里通过两个扩展方法分别处理不同的状态。

  • 选中状态,播放动画并设置icon颜色
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * 选中状态
     */
    fun TabLayout.Tab.setSelected() {
        this.customView?.let {
            val textView = it.findViewById<TextView>(R.id.tv_tab_text)
            val selectedColor = ContextCompat.getColor(this@TabLayoutActivity, R.color.colorPrimary)
            textView.setTextColor(selectedColor)

            val imageView = it.findViewById<LottieAnimationView>(R.id.lav_tab_img)
            if (!imageView.isAnimating) {
                imageView.playAnimation()
            }
            setLottieColor(imageView, true)
        }
    }
  • 未选中状态,停止动画并还原初始状态,然后设置icon颜色
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * 未选中状态
     */
    fun TabLayout.Tab.setUnselected() {
        this.customView?.let {
            val textView = it.findViewById<TextView>(R.id.tv_tab_text)
            val unselectedColor = ContextCompat.getColor(this@TabLayoutActivity, R.color.black)
            textView.setTextColor(unselectedColor)

            val imageView = it.findViewById<LottieAnimationView>(R.id.lav_tab_img)
            if (imageView.isAnimating) {
                imageView.cancelAnimation()
                imageView.progress = 0f // 还原初始状态
            }
            setLottieColor(imageView, false)
        }
    }

关于修改lottie icon的颜色,目前网上的答案参差不齐,还是源码来的直接。

源码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    if (ta.hasValue(R.styleable.LottieAnimationView_lottie_colorFilter)) {
      int colorRes = ta.getResourceId(R.styleable.LottieAnimationView_lottie_colorFilter, -1);
      ColorStateList csl = AppCompatResources.getColorStateList(getContext(), colorRes);
      SimpleColorFilter filter = new SimpleColorFilter(csl.getDefaultColor());
      KeyPath keyPath = new KeyPath("**");
      LottieValueCallback<ColorFilter> callback = new LottieValueCallback<>(filter);
      addValueCallback(keyPath, LottieProperty.COLOR_FILTER, callback);
    }

所以直接借鉴即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * set lottie icon color
     */
    private fun setLottieColor(imageView: LottieAnimationView?, isSelected: Boolean) {
        imageView?.let {
            val color = if (isSelected) R.color.colorPrimary else R.color.black
            val csl = AppCompatResources.getColorStateList(this@TabLayoutActivity, color)
            val filter = SimpleColorFilter(csl.defaultColor)
            val keyPath = KeyPath("**")
            val callback = LottieValueCallback<ColorFilter>(filter)
            it.addValueCallback(keyPath, LottieProperty.COLOR_FILTER, callback)
        }
    }

动画文件的下载网站推荐: lordicon

15.关联ViewPager

15.1 编写FragmentPagerAdapter
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    private inner class SimpleFragmentPagerAdapter constructor(fm: FragmentManager) :
        FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

        private val tabTitles = arrayOf("Android", "Kotlin", "Flutter")
        private val fragment = arrayOf(Fragment1(), Fragment2(), Fragment3())

        override fun getItem(position: Int): Fragment {
            return fragment[position]
        }

        override fun getCount(): Int {
            return fragment.size
        }

        override fun getPageTitle(position: Int): CharSequence {
            return tabTitles[position]
        }
    }
15.2 给ViewPager设置Adapter
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mBinding.viewPager.adapter = SimpleFragmentPagerAdapter(supportFragmentManager)
15.3 给TabLayout关联ViewPager
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mBinding.tabLayout1.setupWithViewPager(mBinding.viewPager)

以上即可把TabLayoutViewPager关联起来,TabLayout的Tab也会由FragmentPagerAdapter中的标题自动生成。

15.4 setupWithViewPager源码分析

究竟是怎么关联起来的呢? 下面是setupWithViewPager中的部分源码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        if (viewPager != null) {
            this.viewPager = viewPager;
            if (this.pageChangeListener == null) {
            	// 步骤1
                this.pageChangeListener = new TabLayout.TabLayoutOnPageChangeListener(this);
            }

            this.pageChangeListener.reset();
            viewPager.addOnPageChangeListener(this.pageChangeListener);
            // 步骤2
            this.currentVpSelectedListener = new TabLayout.ViewPagerOnTabSelectedListener(viewPager);
            // 步骤3
            this.addOnTabSelectedListener(this.currentVpSelectedListener);
            PagerAdapter adapter = viewPager.getAdapter();
            if (adapter != null) {
                this.setPagerAdapter(adapter, autoRefresh);
            }

            if (this.adapterChangeListener == null) {
                this.adapterChangeListener = new TabLayout.AdapterChangeListener();
            }

            this.adapterChangeListener.setAutoRefresh(autoRefresh);
            // 步骤4
            viewPager.addOnAdapterChangeListener(this.adapterChangeListener);
            this.setScrollPosition(viewPager.getCurrentItem(), 0.0F, true);
        }
  1. 先是创建了TabLayout.TabLayoutOnPageChangeListener,并设置给了viewPager.addOnPageChangeListener。
  2. 然后又创建了TabLayout.ViewPagerOnTabSelectedListener(viewPager),并传入当前viewPager,然后设置给了addOnTabSelectedListener。
  3. 所以,经过这种你来我往的操作之后,设置TabLayout的选中下标和设置ViewPager的选中下标,其实效果是一毛一样的,因为联动起来了…

另外,FragmentPagerAdapter已经废弃了,官方推荐使用viewpager2FragmentStateAdapter 代替。

Deprecated Switch to androidx.viewpager2.widget.ViewPager2 and use androidx.viewpager2.adapter.FragmentStateAdapter instead.

16.常用API整理

16.1 TabLayout

API

含义

background

TabLayout背景颜色

tabIndicator

指示器(一般下划线)

tabIndicatorColor

指示器颜色

tabIndicatorHeight

指示器高度,不显示写0dp

tabIndicatorFullWidth

指示器宽度是否撑满item

tabMode

tab显示形式,1.auto自动,2.fixed固定宽度,3.scrollable可滑动

tabSelectedTextColor

tab选中文字颜色

tabTextColor

tab未选中文字颜色

tabRippleColor

tab点击效果颜色

tabGravity

tab对齐方式

tabTextAppearance

tab文本样式,可引用style

tabMaxWidth

tab最大宽度

tabMinWidth

tab最小宽度

setupWithViewPager

tabLayout关联ViewPager

addOnTabSelectedListener

tab选中监听事件

16.2 TabLayout.Tab

API

含义

setCustomView

设置tab自定义view

setIcon

设置tab icon

setText

设置tab文本

getOrCreateBadge

获取或创建badge(小红点)

removeBadge

移除badge(小红点)

select

设置tab选中

isSelected

获取tab选中状态

16.3 BadgeDrawable

API

含义

setVisible

设置显示状态

setBackgroundColor

设置小红点背景颜色

getBadgeTextColor

设置小红点文本颜色

setNumber

设置小红点显示数量

clearNumber

清除小红点数量

setBadgeGravity

设置小红点位置对齐方式

Github

https://github.com/yechaoa/MaterialDesign

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
每个数据科学专家都应该知道的六个概率分布
摘要:概率分布在许多领域都很常见,包括保险、物理、工程、计算机科学甚至社会科学,如心理学和医学。它易于应用,并应用很广泛。本文重点介绍了日常生活中经常能遇到的六个重要分布,并解释了它们的应用。 介绍 假设你是一所大学的老师。在对一周的作业进行了检查之后,你给所有的学生打了分数。你把这些打了分数的论文交给大学的数据录入人员,并告诉他创建一个包含所有学生成绩的电子表格。但这个人却只存储了成绩,而没有包含对应的学生。 他又犯了另一个错误,在匆忙中跳过了几项,但我们却不知道丢了谁的成绩。我们来看看如何来解决这个问题
小莹莹
2018/04/24
1.3K0
每个数据科学专家都应该知道的六个概率分布
从贝叶斯定理到概率分布:综述概率论基本定义
选自 Medium & analyticsvidhya 本文从最基础的概率论到各种概率分布全面梳理了基本的概率知识与概念,这些概念可能会帮助我们了解机器学习或开拓视野。这些概念是数据科学的核心,并经常出现在各种各样的话题上。重温基础知识总是有益的,这样我们就能发现以前并未理解的新知识。 简介 在本系列文章中,我想探讨一些统计学上的入门概念,这些概念可能会帮助我们了解机器学习或开拓视野。这些概念是数据科学的核心,并经常出现在各种各样的话题上。重温基础知识总是有益的,这样我们就能发现以前并未理解的新知识,
小莹莹
2018/04/24
1.2K0
从贝叶斯定理到概率分布:综述概率论基本定义
可视化数据科学中的概率分布以帮你更好地理解各种分布
在某些分布假设下,某些机器学习模型被设计为最佳工作。因此,了解我们正在使用哪个发行版可以帮助我们确定最适合使用哪些模型。
计算机与AI
2020/11/19
1K0
可视化数据科学中的概率分布以帮你更好地理解各种分布
数据科学中常见的6个概率分布及Python实现
拥有良好的统计背景对于数据科学家的日常工作可能会大有裨益。每次我们开始探索新的数据集时,我们首先需要进行探索性数据分析(EDA),以了解某些特征的概率分布是什么。如果我们能够了解数据分布中是否存在特定模式,则可以量身定制最适合我们的机器学习模型。这样,我们将能够在更短的时间内获得更好的结果(减少优化步骤)。实际上,某些机器学习模型被设计为在某些分布假设下效果最佳。因此,了解我们正在使用哪个概率分布可以帮助我们确定最适合使用哪个模型。
刘早起
2020/06/30
1.4K0
数据科学中常见的6个概率分布及Python实现
数据挖掘学习小组之(概率分布)
随机变量(random variable)表示随机试验各种结果的实值单值函数。随机事件不论与数量是否直接有关,都可以数量化,即都能用数量化的方式表达!
数据处理与分析
2019/08/05
7330
机器学习统计概率分布全面总结(Python)
在平时的科研中,我们经常使用统计概率的相关知识来帮助我们进行城市研究。因此,掌握一定的统计概率相关知识非常有必要。
算法进阶
2023/12/26
5950
机器学习统计概率分布全面总结(Python)
11种概率分布,你了解几个?
了解常见的概率分布十分必要,它是概率统计的基石。这是昨天推送的 从概率统计到深度学习,四大技术路线图谱,都在这里!文章中的第一大技术路线图谱如下所示,图中左侧正是本文要总结的所有常见概率分布。
double
2019/10/08
20.6K0
11种概率分布,你了解几个?
​常用的连续概率分布汇总
在数学中,连续型随机变量的概率密度函数(在不至于混淆时可以简称为密度函数)是一个描述这个随机变量的输出值,在某个确定的取值点附近的可能性的函数。而随机变量的取值落在某个区域之内的概率则为概率密度函数在这个区域上的积分。
deephub
2021/11/08
1.9K0
​常用的连续概率分布汇总
统计中的各种分布
1. 伯努利分布:伯努利分布:伯努利试验单次随机试验,只有"成功(值为1)"或"失败(值为0)"这两种结果。又名两点分布或者0-1分布。
小末快跑
2020/07/29
2.1K0
统计中的各种分布
python实现10种概率分布(附代码)
在概率论和统计学中,均匀分布也被称为矩形分布。这种分布可以通过两个参数a和b来定义,它们分别是数轴上的最小值和最大值,因此通常表示为U(a, b)。
皮大大
2024/08/07
8400
Python实现 8 个概率分布公式及可视化
概率和统计知识是数据科学和机器学习的核心; 我们需要统计和概率知识来有效地收集、审查、分析数据。
数据STUDIO
2022/05/24
1.3K0
Python实现 8 个概率分布公式及可视化
​常见的8个概率分布公式和可视化
来源:Deephub Imba本文约2800字,建议阅读8分钟本文我们将介绍一些常见的分布并通过Python 代码进行可视化以直观地显示它们。 概率和统计知识是数据科学和机器学习的核心;我们需要统计和概率知识来有效地收集、审查、分析数据。 现实世界中有几个现象实例被认为是统计性质的(即天气数据、销售数据、财务数据等)。这意味着在某些情况下,我们已经能够开发出方法来帮助我们通过可以描述数据特征的数学函数来模拟自然。 “概率分布是一个数学函数,它给出了实验中不同可能结果的发生概率。” 了解数据的分布有助于更好
数据派THU
2022/04/29
1.1K0
​常见的8个概率分布公式和可视化
机器学习领域必知必会的12种概率分布(附Python代码实现)
机器学习有其独特的数学基础,我们用微积分来处理变化无限小的函数,并计算它们的变化;我们使用线性代数来处理计算过程;我们还用概率论与统计学建模不确定性。在这其中,概率论有其独特的地位,模型的预测结果、学习过程、学习目标都可以通过概率的角度来理解。
Datawhale
2019/10/09
4360
机器学习领域必知必会的12种概率分布(附Python代码实现)
一文搞懂常见概率分布的直觉与联系
数据科学,不管它到底是什么,其影响力已不可忽视。“数据科学家比任何软件工程师都更擅长统计学。”你可能在本地的技术聚会或者黑客松上无意中听到一个专家这么说。应用数学家大仇得报,毕竟从咆哮的二十年代起人们就不怎么谈论统计学了。以前聊天的时候,像你这样的工程师,会因为分析师从来没听说过Apache Bikeshed(口水仗)这个分布式评论格式编排项目而发出啧啧声。现在,你却突然发现人们在聊置信区间的时候不带上你了。为了融入聊天,为了重新成为聚会的灵魂人物,你需要恶补下统计学。不用学到正确理解的程度,只需学到让人们(基于基本的观测)觉得你可能理解了的程度。
zenRRan
2019/11/20
1.9K0
一文搞懂常见概率分布的直觉与联系
算法入门(三) -- 概率论基础
概率知识是算法学习中较为重要的一环,下面我们就来回顾一下算法中需要用到的概率基础知识,以及他们的公式和分布图像。
万事可爱^
2025/01/23
1300
算法入门(三) -- 概率论基础
数据科学17 | 统计推断-期望方差和常见概率分布
随机变量的分布的中心就是其均值或期望值。均值改变,分布会如同均值向左或向右移动。统计推断中,用样本均值估计总体分布的均值(期望值),样本量越多,样本均值约接近总体均值。
王诗翔呀
2020/07/03
1.7K0
数据科学17 | 统计推断-期望方差和常见概率分布
深度学习必懂的13种概率分布
作为机器学习从业者,你需要知道概率分布相关的知识。这里有一份最常见的基本概率分布教程,大多数和使用 python 库进行深度学习有关。
AI研习社
2019/10/22
8410
深度学习必懂的13种概率分布
深度学习必须掌握的 13 种概率分布
深度学习从业者,你需要知道概率分布相关的知识。这里有一份最常见的基本概率分布教程,大多数和使用 python 库进行深度学习有关。
算法进阶
2023/08/28
2670
深度学习必须掌握的 13 种概率分布
对真实的世界建模-概率论(分布&计算)
前段时间觉得概率论不可理喻,再拿起的时候已经少了些许晦涩之感。(我们的自然语言不明确,概率论是离真实建模最近的学科,所以觉得难学,是因为我们逐渐走向精确)
云深无际
2024/10/08
2070
对真实的世界建模-概率论(分布&计算)
常见概率分布及在R中的应用
常见概率分布 离散型 1.二项分布Binomial distribution:binom 二项分布指的是N重伯努利实验,记为X ~ b(n,p),E(x)=np,Var(x)=np(1-p) pbinom(q,size,prob), q是特定取值,比如pbinom(8,20,0.2)指第8次伯努利实验的累计概率。size指总的实验次数,prob指每次实验成功发生的概率 dbinom(x,size,prob), x同上面的q同含义。dfunction()对于离散分布来说结果是特定值的概率,对连续变量来说是密度
机器学习AI算法工程
2018/03/13
3.6K0
相关推荐
每个数据科学专家都应该知道的六个概率分布
更多 >
LV.0
这个人很懒,什么都没有留下~
目录
  • 前言
  • 效果图
  • 简介
  • 功能拆解
    • 1.基础实现
      • 1.1 xml动态写法
      • 1.2 xml静态写法
      • 1.3 kotlin/java代码写法
    • 2.添加图标
    • 3.字体大小、加粗
    • 4.去掉Tab长按提示文字
    • 5.去掉下划线indicator
    • 6.下划线的样式
    • 7.下划线的宽度
    • 8.Tab分割线
    • 9.TabLayout样式
    • 10.Tab添加小红点
    • 11.获取隐藏的Tab
    • 12.Tab宽度自适应
    • 13.自定义Item View
    • 14.使用Lottie
    • 15.关联ViewPager
      • 15.1 编写FragmentPagerAdapter
      • 15.2 给ViewPager设置Adapter
      • 15.3 给TabLayout关联ViewPager
      • 15.4 setupWithViewPager源码分析
    • 16.常用API整理
      • 16.1 TabLayout
      • 16.2 TabLayout.Tab
      • 16.3 BadgeDrawable
  • Github
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档