zoukankan      html  css  js  c++  java
  • TabLayout设置下划线(Indicator)宽度

    再战TabLayout之下划线宽度

    这周的需求搞定之后,想到之前有一个小瑕疵,反正没什么事,索性较量较量

     

    如图官方原版就是小瑕疵,反射版本就是最终

    解决方案-Demo源码

    先讲解决方案。直接贴代码(要在tabLayout添加完所有的tab后调用)

     

    1. public void reflex(final TabLayout tabLayout){  
    2.     //了解源码得知 线的宽度是根据 tabView的宽度来设置的  
    3.     tabLayout.post(new Runnable() {  
    4.         @Override  
    5.         public void run() {  
    6.             try {  
    7.                 //拿到tabLayout的mTabStrip属性  
    8.                 LinearLayout mTabStrip = (LinearLayout) tabLayout.getChildAt(0);  
    9.   
    10.                 int dp10 = dip2px(tabLayout.getContext(), 10);  
    11.   
    12.                 for (int i = 0; i < mTabStrip.getChildCount(); i++) {  
    13.                     View tabView = mTabStrip.getChildAt(i);  
    14.   
    15.                     //拿到tabView的mTextView属性  tab的字数不固定一定用反射取mTextView  
    16.                     Field mTextViewField = tabView.getClass().getDeclaredField("mTextView");  
    17.                     mTextViewField.setAccessible(true);  
    18.   
    19.                     TextView mTextView = (TextView) mTextViewField.get(tabView);  
    20.   
    21.                     tabView.setPadding(0, 0, 0, 0);  
    22.   
    23.                     //因为我想要的效果是   字多宽线就多宽,所以测量mTextView的宽度  
    24.                     int width = 0;  
    25.                     width = mTextView.getWidth();  
    26.                     if (width == 0) {  
    27.                         mTextView.measure(0, 0);  
    28.                         width = mTextView.getMeasuredWidth();  
    29.                     }  
    30.   
    31.                     //设置tab左右间距为10dp  注意这里不能使用Padding 因为源码中线的宽度是根据 tabView的宽度来设置的  
    32.                     LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tabView.getLayoutParams();  
    33.                     params.width = width ;  
    34.                     params.leftMargin = dp10;  
    35.                     params.rightMargin = dp10;  
    36.                     tabView.setLayoutParams(params);  
    37.   
    38.                     tabView.invalidate();  
    39.                 }  
    40.   
    41.             } catch (NoSuchFieldException e) {  
    42.                 e.printStackTrace();  
    43.             } catch (IllegalAccessException e) {  
    44.                 e.printStackTrace();  
    45.             }  
    46.         }  
    47.     });  
    48.   
    49. }  




    问题解决思路

    第一反应是找系统的方法和属性

    发现只有设置tabIndicatorHeight的属性 并没有宽度的属性

    接着百度,一百度就看到几个博客,宣称可以解决这个问题,我们先看看他们的解决方案

    传送门这种解决方案仅限于所有的tabView的text字数都是相同字数,比如所有的图中所有的tab字数都是2个。其实思路是错的,没有研究源码详细实现

    他的思路是设置tabView的padding为0,并且设置了margin

    这种方案错误的原因是,tablayout会强制设置tabView的宽度为  几个tabView中最宽的宽度,比如4个字的tabview和2个字的tabview的组合,两个tabview的宽度强制为4个字的tabview的宽度

     下面会证实这一点

    那只有查源码了呗,tab的创建是 tablayout.addTab();方法构造的 具体代码如下

    1. tabLayout.addTab(tabLayout.newTab().setText("生鲜食品"));  



    直接查这个方法,通过几个重载方法(addTab(Tab tab)->addTab(Tab tab,boolean setSelected)->addTab( Tab tab, int position, boolean setSelecte);  跳转如下代码


     

    从注释看就是添加一个tab到这个layout上  具体实现是在addTabView(Tab tab)里面,继续看这个方法

     


    可以看到最后添加到mTabStrip中,我们再来看看TabView里面有什么东西

     


     

    光从属性可以看出TabView可以自定义的,而且并没有发现Indicator线的痕迹,我猜测他可能放在layout(mTabStrip)里面,因为我以前写这样效果  这样写过,那我们就来看mTabStrip

     


     

    查看类中,发现mSelectedIndicatorHeight,眼睛一亮,下划线高度!!,就是画线的地方。追踪mIndicatorLeft和mIndicatorRight的来路,几经追踪,发现如下代码

     


     

    如图,selectedTitle就是TabView,直接获取了左边坐标和右边坐标,也就说是线的宽度就是tabview的宽度,那疑问又来了,为什么我们两个字的tabView和4个字的tabView是一样宽度,先去看看SlidingTabStrip的onMeasure方法,如下图

     


     

    我日,我怎么感觉写TabLayout这个类的人是强迫症,有没有?第一个for循环干的事就是记录下来,所有tabView中的最大宽度,第二个循环就是把所有的tabView的宽度设置为第一个循环得到的最大宽!!!

     

    罪魁祸首是找到了,这时候能动态代理一个重写onMeasure方法的SlidingTabStrip对象塞进去,也可以解决这个问题,你会发现SlidingTabStrip是private的!!!!!!!

     

    思路一转,系统是强制设置所有tabview的宽度为 最宽那个tabview的宽度,那我重新设置一遍tabView的宽度即可,解决问题(其实中间还尝试过调用setIndicatorPosition方法,但是系统源码,在多个时期调用这个方法,所以毙掉了)

    那最上面的解决方案就来了

     

    1、通过反射拿到SlidingTabStrip,通过遍历拿到tabview,继续通过反射拿到textview,然后设置Tabview的宽度为textview的宽度

     

    2、为了美观我们可以设置一下tabview的margin,不设置会连在一起

    转载 https://blog.csdn.net/qq_35473951/article/details/78653567

  • 相关阅读:
    690. Employee Importance 员工重要性
    682. Baseball Game 棒球比赛计分
    680. Valid Palindrome II 有效的回文2
    553. Optimal Division 最佳分割
    服务器oracle数据库定时备份
    数据类型和抽象数据类型
    静态链表和动态链表的区别:
    it网站
    java 移动开发获取多级下拉框json数据的类和mobile-select-area插件
    redis持久化之aof篇
  • 原文地址:https://www.cnblogs.com/Android-FJH/p/9198453.html
Copyright © 2011-2022 走看看