一篇文章带你解决Android-TabLayout缺陷,不同方式带你改变Tab下划线宽度【实践总结】

这就是绘制的选中Tab的Indicator,高度是,宽是mIndicatorRight - mIndicatorLeft。那么者两个值是从哪儿来的呢?在方法中:// 选中的TabView// left 和right 的值} else {// 设置mIndicatorLeft和mIndicatorRightif (left!
摘要由CSDN通过智能技术生成

}
}

这就是绘制的选中Tab的Indicator,高度是mSelectedIndicatorHeight,宽是mIndicatorRight - mIndicatorLeft 。那么者两个值是从哪儿来的呢?在updateIndicatorPosition方法中:

private void updateIndicatorPosition() {
// 选中的TabView
final View selectedTitle = getChildAt(mSelectedPosition);
int left, right;

if (selectedTitle != null && selectedTitle.getWidth() > 0) {
// left 和right 的值
left = selectedTitle.getLeft();
right = selectedTitle.getRight();

if (mSelectionOffset > 0f && mSelectedPosition < getChildCount() - 1) {
// Draw the selection partway between the tabs
View nextTitle = getChildAt(mSelectedPosition + 1);
left = (int) (mSelectionOffset * nextTitle.getLeft() +
(1.0f - mSelectionOffset) * left);
right = (int) (mSelectionOffset * nextTitle.getRight() +
(1.0f - mSelectionOffset) * right);
}
} else {
left = right = -1;
}
// 设置mIndicatorLeft和mIndicatorRight
setIndicatorPosition(left, right);
}

void setIndicatorPosition(int left, int right) {
if (left != mIndicatorLeft || right != mIndicatorRight) {
// If the indicator’s left/right has changed, invalidate
mIndicatorLeft = left;
mIndicatorRight = right;
ViewCompat.postInvalidateOnAnimation(this);
}
}

**从上面的代码就可以看出,Indicator(Tab选中下划线)的宽度其实就是TabView的宽度,那么TabView的宽度是多少呢?在SlidingTabStriponMeasure方法中,为TabView设置了宽度。**请看代码:

@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

//以上省略
if (mMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER) {
final int count = getChildCount();

// First we’ll find the widest tab
//google的工程师注释写的非常清楚:第一步,找出宽度最长的Tab
int largestTabWidth = 0;
for (int i = 0, z = count; i < z; i++) {
View child = getChildAt(i);
if (child.getVisibility() == VISIBLE) {
largestTabWidth = Math.max(largestTabWidth, child.getMeasuredWidth());
}
}

if (largestTabWidth <= 0) {
// If we don’t have a largest child yet, skip until the next measure pass
return;
}

final int gutter = dpToPx(FIXED_WRAP_GUTTER_MIN);
boolean remeasure = false;

if (largestTabWidth * count <= getMeasuredWidth() - gutter * 2) {
// If the tabs fit within our width minus gutters, we will set all tabs to have
// the same width
// 第二步:将所有Tab的宽度都设置为largestTabWidth
for (int i = 0; i < count; i++) {
final LinearLayout.LayoutParams lp =
(LayoutParams) getChildAt(i).getLayoutParams();
if (lp.width != largestTabWidth || lp.weight != 0) {
lp.width = largestTabWidth;
lp.weight = 0;
remeasure = true;
}
}
} else {
// If the tabs will wrap to be larger than the width minus gutters, we need
// to switch to GRAVITY_FILL
mTabGravity = GRAVITY_FILL;
updateTabViews(false);
remeasure = true;
}


//以下省略
}
}

这个方法很简单,一看就明白,有两个步骤:

1, 一个for循环,找出宽度最大的一个TabView
2, 再一个for 循环,设置所有TabView的宽度为最长那个TabView的宽度,即largestTabWidth

这就知道为什么前面提到的所有Tab 一样宽,不管长的还是短的。

另外一个点: 上面的onMeasure 中,执行的条件是mMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER ,如果是其他条件,请看updateTabViews:

void updateTabViews(final boolean requestLayout) {
for (int i = 0; i < mTabStrip.getChildCount(); i++) {

  • 10
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值