如何自定义选项卡指示器的宽度?

12

我想要这种类型的选项卡指示器,我该如何实现?我已经尝试了所有可绘制的可选择处理程序的解决方案,但是没有得到任何东西。

enter image description here


在您的drawable文件夹中添加指示器图像。 - Qandil Tariq
请查看我的最新解决方案:https://dev59.com/YlcO5IYBdhLWcg3wgRsG#58381087 - Chenxi
4个回答

12

有一个更简单的方法来实现这个,只需提供一个自定义指示器的 drawableapp:tabIndicator

例如,在这种情况下:

underline.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <item android:gravity="center">
        <shape>
            <size
                android:width="22dp"
                android:height="2dp" />

            <corners android:radius="2dp" />

            <solid android:color="#FF0000" />
        </shape>
    </item>
</layer-list>

将其添加到您的TabLayout中的方法如下:

<com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/_16dp"
        android:layout_marginTop="@dimen/_16dp"
        app:tabIndicator="@drawable/underline"
        app:tabIndicatorColor="@color/offers_header_text"
        app:tabIndicatorHeight="4dp"
        app:tabMode="scrollable"
        app:tabRippleColor="@null" />

8

试试这个:

public void wrapTabIndicatorToTitle(TabLayout tabLayout, int externalMargin, int internalMargin) {
    View tabStrip = tabLayout.getChildAt(0);
    if (tabStrip instanceof ViewGroup) {
        ViewGroup tabStripGroup = (ViewGroup) tabStrip;
        int childCount = ((ViewGroup) tabStrip).getChildCount();
        for (int i = 0; i < childCount; i++) {
            View tabView = tabStripGroup.getChildAt(i);
            //set minimum width to 0 for instead for small texts, indicator is not wrapped as expected
            tabView.setMinimumWidth(0);
            // set padding to 0 for wrapping indicator as title
            tabView.setPadding(0, tabView.getPaddingTop(), 0, tabView.getPaddingBottom());
            // setting custom margin between tabs
            if (tabView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
                ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) tabView.getLayoutParams();
                if (i == 0) {
                    // left
                    settingMargin(layoutParams, externalMargin, internalMargin);
                } else if (i == childCount - 1) {
                    // right
                    settingMargin(layoutParams, internalMargin, externalMargin);
                } else {
                    // internal
                    settingMargin(layoutParams, internalMargin, internalMargin);
                }
            }
        }


        tabLayout.requestLayout();
    }
}

private void settingMargin(ViewGroup.MarginLayoutParams layoutParams, int start, int end) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        layoutParams.setMarginStart(start);
        layoutParams.setMarginEnd(end);
    } else {
        layoutParams.leftMargin = start;
        layoutParams.rightMargin = end;
    }
}

在Java文件中设置视图页面后,添加:

wrapTabIndicatorToTitle(tabLayout,80,80);

是的,使用这个解决方案我可以得到选项卡标题宽度指示器,但我想要左右两侧的填充,并且指示器应该像图片中一样居中。 - Chetan Shelake
你可以尝试将该值增加到100或者使用自定义选项卡。TextView和View,你需要这个解决方案吗? - Vidhi Dave

3

一个简单的解决方案是:

tabLayout.setTabIndicatorFullWidth(false);

但它可以与最新的依赖项一起使用,例如

implementation 'com.google.android.material:material:1.0.0'

1
这将使我的测试中指示器宽度与文本宽度相同。 - ssynhtn

1
对于支持库版本28.0.0,我想到了一种解决方案,替换TabLayout.tabViewContentBounds对象为自定义对象,这样你就可以在此处应用你的逻辑,以任何你想要的方式修改指示器位置。
这里是自定义的RectF类(谢天谢地它不是final类)。
public class TabIndicatorRectF extends RectF implements Serializable {
    private RectF temp = new RectF();
    private IndicatorBoundsModifier indicatorBoundsModifier;

    public TabIndicatorRectF(IndicatorBoundsModifier indicatorBoundsModifier) {
        this.indicatorBoundsModifier = indicatorBoundsModifier;
    }

    private interface IndicatorBoundsModifier {
        void modify(RectF bounds);
    }

    @Override
    public void set(float left, float top, float right, float bottom) {
        temp.set(left, top, right, bottom);
        indicatorBoundsModifier.modify(temp);

        super.set(temp);
    }

    public void replaceBoundsRectF(TabLayout tabLayout) {
        try {
            Field field = TabLayout.class.getDeclaredField("tabViewContentBounds");
            field.setAccessible(true);
            field.set(tabLayout, this);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }

    }

    public static class FixedWidthModifier implements IndicatorBoundsModifier {
        private float halfWidth;

        public FixedWidthModifier(float width) {
            this.halfWidth = Math.abs(width) / 2;
        }

        @Override
        public void modify(RectF bounds) {
            float centerX = bounds.centerX();
            bounds.left = centerX - halfWidth;
            bounds.right = centerX + halfWidth;
        }
    }

}

现在调用这个。
new TabIndicatorRectF(
            new TabIndicatorRectF.FixedWidthModifier(
                    getResources().getDimension(R.dimen.tab_indicator_width)))
            .replaceBoundsRectF(tabLayout);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接