关于第三方库SmartTabLayout的一点小修改
theme: channing-cyan
小知识,大挑战!本文正在参与「程序员必备小知识」创作活动
本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。
介绍
项目中目前使用了SmartTabLayout来作为ViewPager的选项卡
大家可以看到下面的指示器会跟随着滑动而变的很扁,一开始我感觉还挺好后面越看越奇怪,直到有一天新的需求出来了,所有选项卡下方指示器都不允许变扁,目前为止这个库都没有提供这个取消变扁的方法,我们只能深入源码了
分析
首先我们项目时自定义的一个选项卡,而且这个库也暴露了一个方法可以让我们获取指定下标的选项卡
mSmart.getTabAt(i)
上面的代码会返回一个View,我们在xml
中设置的选项卡文字根布局就是TextView,所以这个获取的也是TextView
xml中配置
<com.ogaclejapan.smarttablayout.SmartTabLayout
android:id="@+id/smart"
android:layout_width="match_parent"
android:layout_height="50dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:stl_customTabTextLayoutId="@layout/item_tablayout_option"
app:stl_customTabTextViewId="@id/item_tablayout_text"
app:stl_defaultTabTextHorizontalPadding="14dp"
app:stl_defaultTabTextMinWidth="0dp"
app:stl_indicatorColor="@color/teal_200"
app:stl_indicatorCornerRadius="5dp"
app:stl_indicatorGravity="bottom"
app:stl_indicatorWidth="12dp" />
现在就点进去看看吧
一目了然,一般来说这种情况tabStrip
一定是选项卡了,或者与选项卡及其相关,点到他的类看看吧
代码我就不放太多了,翻译和使用的一些地方就已经表明他是选项卡了.接下来我们来找指示器绘制的地方吧
命名规范的好处就体现出来了,我直接搜draw或者Indicator不一会就能找到目的地,真不戳,接着看代码吧
switch (indicatorGravity) {
case GRAVITY_TOP:
center = indicatorThickness / 2f;
top = center - (thickness / 2f);
bottom = center + (thickness / 2f);
break;
case GRAVITY_CENTER:
center = height / 2f;
top = center - (thickness / 2f);
bottom = center + (thickness / 2f);
break;
case GRAVITY_BOTTOM:
default:
center = height - (indicatorThickness / 2f);
top = center - (thickness / 2f);
bottom = center + (thickness / 2f);
}
这一步就很简单,判断xml中属性来设置对应的参数,以达到控制指示器位置的目的.我们项目中一直都是bottom所以重点关注下GRAVITY_BOTTOM
bottom没有做任何操作,直接转给default.这里面参数有点多我们看看谁调用了drawIndicator
``` private void drawDecoration(Canvas canvas) { final int height = getHeight(); final int width = getWidth(); final int tabCount = getChildCount(); final SmartTabLayout.TabColorizer tabColorizer = getTabColorizer(); final boolean isLayoutRtl = Utils.isLayoutRtl(this);
if (indicatorInFront) { drawOverline(canvas, 0, width); drawUnderline(canvas, 0, width, height); }
// Thick colored underline below the current selection if (tabCount > 0) { View selectedTab = getChildAt(selectedPosition); int selectedStart = Utils.getStart(selectedTab, indicatorWithoutPadding); int selectedEnd = Utils.getEnd(selectedTab, indicatorWithoutPadding); int left; int right; if (isLayoutRtl) { left = selectedEnd; right = selectedStart; } else { left = selectedStart; right = selectedEnd; }
int color = tabColorizer.getIndicatorColor(selectedPosition);
float thickness = indicatorThickness;
if (selectionOffset > 0f && selectedPosition < (getChildCount() - 1)) {
int nextColor = tabColorizer.getIndicatorColor(selectedPosition + 1);
if (color != nextColor) {
color = blendColors(nextColor, color, selectionOffset);
}
// Draw the selection partway between the tabs
float startOffset = indicationInterpolator.getLeftEdge(selectionOffset);
float endOffset = indicationInterpolator.getRightEdge(selectionOffset);
float thicknessOffset = indicationInterpolator.getThickness(selectionOffset);
View nextTab = getChildAt(selectedPosition + 1);
int nextStart = Utils.getStart(nextTab, indicatorWithoutPadding);
int nextEnd = Utils.getEnd(nextTab, indicatorWithoutPadding);
if (isLayoutRtl) {
left = (int) (endOffset * nextEnd + (1.0f - endOffset) * left);
right = (int) (startOffset * nextStart + (1.0f - startOffset) * right);
} else {
left = (int) (startOffset * nextStart + (1.0f - startOffset) * left);
right = (int) (endOffset * nextEnd + (1.0f - endOffset) * right);
}
thickness = thickness * thicknessOffset;
}
//绘制指示器
drawIndicator(canvas, left, right, height, thickness, color);
}
if (!indicatorInFront) { drawOverline(canvas, 0, width); drawUnderline(canvas, 0, getWidth(), height); }
// Vertical separators between the titles drawSeparator(canvas, height, tabCount);
} ```
好家伙,上面一堆计算,怕了怕了,还是回去吧,不过粗粗的看一眼还是能看出来个大概,就是滑动的距离,咔咔咔一顿处理,就得出了一定的数值.回到原来的方法吧.回来后把目光聚集到这个地方
if (indicatorWidth == AUTO_WIDTH) {
indicatorRectF.set(left, top, right, bottom);
} else {
float padding = (Math.abs(left - right) - indicatorWidth) / 2f;
indicatorRectF.set(left + padding, top, right - padding, bottom);
}
把计算过的参数给传递进去了,点进去看看
原来如此哈
case GRAVITY_BOTTOM:
default:
center = height - (indicatorThickness / 2f);
top = center - (thickness / 2f);
bottom = center + (thickness / 2f);
那这个代码就一目了然了,根据滑动距离计算的值来计算它的高度和宽度.我们直接把动态的数据设置成静态的就差不多能达到我们的效果
case GRAVITY_BOTTOM:
default:
center = height - (indicatorThickness / 2f);
top = center - (indicatorThickness / 2f);
bottom = center + (indicatorThickness / 2f);
试一下效果
嘿嘿,简简单单.
后面我写Demo的时候遇到一个贼好笑的事情,因为这个库是歪果仁写的,全是英文,api翻译后更是驴唇不对马嘴,我闲着没事试试api都代表着啥,没想到啊
app:stl_indicatorInterpolation="linear"
设置这个直接就解决上面我分析一大段的东西,我直接吐血而亡.看来我要努力学习英文了
- 学习Android的第十七天
- 这是一个吸猫文章的标题,甚至可以有两行这么多哦
- 学习Android的第四天
- 学习Android的第一天
- 含有边框的TextView-Android
- 电池-Android
- 倒计时封装-Android
- 标题和状态栏滑动渐变(2)-Android
- 标题和状态栏滑动渐变(1)-Android
- 关于选项卡三方库FlycoTabLayout的使用及修改
- 关于第三方库SmartTabLayout的一点小修改
- 关于递归反转链表的思路
- 搜索历史记录的实现-Android
- 感觉让人耳目一新的动画库Lottie
- Android-关于设备唯一ID的奇技淫巧
- 稍微巧妙的双模块联动-ViewPager
- 动画库NineOldAndroids实战自定义悬浮窗
- 关于项目中圆角及特殊圆角的实际使用问题
- 自定义TextView可控制Drawable大小