最近接触到了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:background 和 app: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宽度的两种方案,请自行选择合适自己的方案。如有不正确,请指出,谢谢。