[Android]Tablayout:修改指示器indicator的宽度

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Gods_magic/article/details/81335859

一、问题描述:

最近接触到了Tablayout,需求是要把Tablayout的下划线宽度缩短,或者说使其可以进行自定宽度。

百度上面大多数利用反射,(具体可百度查询),这种方法确实可以把下划线变短,但是同时也会缩短Tab的点击区域,并且过于短后会影响Tab上TextView的UI显示效果。总之,治标不治本,不是我想要的结果。

二、分析源码:

通过查询资料以及对TabLayout的源码进行分析,发现源码中对下划线color以及height都提供了接口,偏偏没有给width提供接口。

进一步发现,下划线是在draw()方法中画出来的,并且定死了下划线的宽度。所以,为啥默认的下划线宽度总是和Tab宽度相同。

想要重写draw方法所在类SlidingTabStrip,来达到目的,发现人家是private 私有内部类,且关于下划线宽度的各种变量都是private,无法重写。

三、解决方案:

网上普遍的反射不可以,又无法重写,经过查找资料和不断尝试,最终总算解决了问题,成功的自定义了下划线宽度。

两种方案:

1.将TabLayout源码copy至本地,修改draw方法,并添加自定义属性,使其可以画出自己想要的indicator宽度

2.替换TabLayout,改用SmartTabLayout

两种方案均与ViewPager搭配使用


四、方案一:

1.提取源码。

在自己的项目路径下新建包,Android Studio改为Project模式,找到design包,我的是27.1.1.版本。

External Libaries -> com.android.support:design-27.1.1 -> classes.jar -> android.support.design -> widget 目录下

TabLayout、AnimationUtils、TabItem、ThemeUtils四个文件copy至自己新建的目录下。

2.自定义属性

tabLineOffset属性为添加的自定义属性,其余copy系统属性。

<!--Custom tabLayout attr -->
    <declare-styleable name="TabLayout">
        <attr name="tabIndicatorColor" format="color" />
        <attr name="tabIndicatorHeight" format="dimension" />
        <attr name="tabContentStart" format="dimension" />
        <attr name="tabBackground" format="reference" />
        <attr name="tabMode">
            <enum name="scrollable" value="0" />
            <enum name="fixed" value="1" />
        </attr>
        <attr name="tabGravity">
            <enum name="fill" value="0" />
            <enum name="center" value="1" />
        </attr>
        <attr name="tabMinWidth" format="dimension" />
        <attr name="tabMaxWidth" format="dimension" />
        <attr name="tabTextAppearance" format="reference" />
        <attr name="tabTextColor" format="color" />
        <attr name="tabSelectedTextColor" format="color" />
        <attr name="tabPaddingStart" format="dimension" />
        <attr name="tabPaddingTop" format="dimension" />
        <attr name="tabPaddingEnd" format="dimension" />
        <attr name="tabPaddingBottom" format="dimension" />
        <attr name="tabPadding" format="dimension" />
        <attr name="tabLineOffset" format="dimension"/>
    </declare-styleable>

3.自定义属性实现

在Tablayout文件中,构造方法中添加自定义属性。

//add custom attributes
mTabLineOffset = a.getDimensionPixelSize(R.styleable.TabLayout_tabLineOffset, 0);

修改draw方法。

@Override
public void draw(Canvas canvas) {
    super.draw(canvas);

    // Thick colored underline below the current selection
    if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
        if (mTabLineOffset == 0) {
             canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
                mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
        } else {
            //Original TabLine Offset
            int width = mIndicatorRight - mIndicatorLeft;
            //Tab Center point coordinate
            int tabCenter = mIndicatorLeft + width / 2;
            RectF oval3 = new RectF(tabCenter - mTabLineOffset, getHeight() - mSelectedIndicatorHeight,
                mIndicatorRight - width / 2 + mTabLineOffset, getHeight());
                canvas.drawRoundRect(oval3, 30, 30, mSelectedIndicatorPaint);
        }
    }
}

4.设置下划线宽度

在xml布局中引入app:tabLineOffset="10dp"通过查看draw方法,

tabLineOffset并不是下划线的实际宽度,想要widh=20dp,则设置app:tabLineOffset="10dp"即可。

 <mysummary.TabLayout.two.my.TabLayout
        android:id="@+id/tab"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        app:tabGravity="center"
        app:tabIndicatorHeight="2dp"
        app:tabLineOffset="10dp"
        app:tabMode="scrollable"
        app:tabSelectedTextColor="@android:color/holo_blue_light"
        app:tabTextAppearance="@style/TabTextStyle"
        app:tabTextColor="@android:color/white" />

5.检查Activity中的TabLayout引用是否为自己的源码而不是引用的系统源码。

6.完成

注:TabLayout中

android:backgroundapp:tabBackground  达到的背景效果相同,

但是app:tabBackground 会使Tab的点击效果消失(类似水波纹)。


五、方案二:

使用支持更多自定义的SmartTabLayout.有我们想要的自定义下划线宽度属性。

属性 描述
stl_indicatorAlwaysInCenter 如果设置为true,选中的标签总是显示在中心(如报刊亭的谷歌应用程序),默认为false
stl_indicatorWithoutPadding 如果设置为真,画出没有填充标签的指标,默认为假
stl_indicatorInFront 在前面的下划线,默认的假画
stl_indicatorInterpolation 指标的行为:: ‘linear’ or ‘smart’
stl_indicatorGravity 指示器的位置: ‘bottom’ or ‘top’ or ‘center’, default ‘bottom’
stl_indicatorColor 指示剂颜色
stl_indicatorColors 该指标的多个颜色,可以设置每个标签的颜色
stl_indicatorThickness 指标的厚度
stl_indicatorWidth 指标的宽度(width), default ‘auto’
stl_indicatorCornerRadius 圆角半径的指示器
stl_overlineColor 顶线的颜色
stl_overlineThickness 顶线厚度
stl_underlineColor 底线的颜色
stl_underlineThickness 底线的厚度
stl_dividerColor 标签的颜色之间的分隔
stl_dividerColors 制表符分隔的多个颜色,可以设置每个标签的颜色
stl_dividerThickness 间隔(divider)的厚度
stl_defaultTabBackground 背景中每个选项卡。一般来说,设置statelistdrawable
stl_defaultTabTextAllCaps 如果设置为真,所有标签的标题将是大写的,default true
stl_defaultTabTextColor 默认的选项卡的文本颜色
stl_defaultTabTextSize 默认的选项卡的文本大小
stl_defaultTabTextHorizontalPadding 默认情况下包含的选项卡的文本布局填充
stl_defaultTabTextMinWidth tab最小宽度
stl_customTabTextLayoutId 布局标识自定义选项卡。如果不指定布局,使用默认选项卡
stl_customTabTextViewId 自定义选项卡布局中的文本视图标识。如果你不确定customtabtextlayoutid,不工作
stl_distributeEvenly 如果设置为真,每个标签都有相同的权重, default false
stl_clickable 如果设置为假,请禁用选项卡的选择, default true
stl_titleOffset 如果设置为“auto_center,滑块位置的标签中会不断向中心。如果指定一个维度将它从左边偏移,默认24dp
stl_drawDecorationAfterTab Draw the decoration(indicator and lines) after drawing of tab, default false 绘制标签后的装饰(指标和线)

1.添加依赖

 compile 'com.ogaclejapan.smarttablayout:library:1.6.1@aar'

2.Activity

public class SmartTablayoutActivity extends AppCompatActivity {

    private SmartTabLayout mSmartTablayout;
    private ViewPager mViewPager;
    private MyAdapter mAdapter;
    public String titles[];

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_smart_tablayout);
        initView();
        initData();
    }

    public void initView() {
        mSmartTablayout = (SmartTabLayout) findViewById(R.id.smart_tablayout);
        mViewPager = (ViewPager) findViewById(R.id.viewPager);
    }

    public void initData() {
        titles = getResources().getStringArray(R.array.channel2);
        mAdapter = new MyAdapter(getSupportFragmentManager(), titles);

        mViewPager.setAdapter(mAdapter);
        mSmartTablayout.setViewPager(mViewPager);
    }
}

3.XML

    <com.ogaclejapan.smarttablayout.SmartTabLayout xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/smart_tablayout"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:background="@color/colorPrimary"
            app:stl_clickable="true"
            app:stl_customTabTextLayoutId="@layout/view_tab_text"
            app:stl_distributeEvenly="true"
            app:stl_dividerThickness="0dp"
            app:stl_indicatorColor="@color/colorAccent"
            app:stl_indicatorGravity="bottom"
            app:stl_indicatorInterpolation="linear"
            app:stl_indicatorThickness="2dp"
            app:stl_indicatorWidth="20dp"
            app:stl_overlineThickness="0dp"
            app:stl_titleOffset="auto_center"
            app:stl_underlineThickness="0dp">

        </com.ogaclejapan.smarttablayout.SmartTabLayout>

        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

4.在Activity中SmartTabLayout用法基本与TabLayout相同,基本完工。运行代码可以发现下划线宽度确实是可以自定义。

当然它还支持很多属性的自定义。

5.SmartTabLayout中并没有设置选中和未选中Tab时的效果,我们可以通过app:stl_customTabTextLayoutId属性引入自定义设置。

  view_tab_text.xml:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tab_text"
    style="@style/Tabtext"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:paddingLeft="20dp"
    android:paddingRight="20dp">
</TextView>

  style.xml:

<style name="Tabtext">
        <item name="android:textColor">@color/selector_tab_text</item>
        <item name="android:textSize">20dp</item>
    </style>

  selector_tab_text.xml:

  在这里设置选中tab的字体颜色,和未选中tab的字体颜色。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@android:color/holo_blue_light" android:state_selected="true" />
    <item android:color="@color/colorWhite100" />
</selector>

6.因为引用了自定义Tab布局,所以原生布局带有的Tab点击效果消失(类似于水波纹)。

我们可以在 view_tab_text.xml 文件中添加想要的水波纹效果。

 android:foreground="@drawable/ripple_app_color"

  ripple_app_color.xml: 水波纹效果

<?xml version="1.0" encoding="utf-8" ?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#292421">
</ripple>

7.完成


以上,是修改TabLayout indicator宽度的两种方案,请自行选择合适自己的方案。如有不正确,请指出,谢谢。

猜你喜欢

转载自blog.csdn.net/Gods_magic/article/details/81335859