安卓支持设计的TabLayout:居中对齐和可滚动模式

112

我正在尝试在我的项目中使用新的Design TabLayout。我希望该布局适应每个屏幕大小和方向,但只能在一个方向上正确显示。

我正在处理将Gravity和Mode设置为我的tabLayout:

    tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
    tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);

因此,我期望如果没有空间,tabLayout 可以滚动,但如果有空间,则居中显示。

从指南中可以看到:

public static final int GRAVITY_CENTER 表示在 TabLayout 中居中布局选项卡的重力。

public static final int GRAVITY_FILL 表示尽可能填充 TabLayout 的重力。仅在 MODE_FIXED 模式下使用此选项有效。

public static final int MODE_FIXED 固定标签同时显示所有选项卡,并且最适合用于需要快速在选项卡之间进行切换的内容。选项卡的最大数量受视图宽度限制。 固定选项卡的宽度相等,基于最宽的选项卡标签。

public static final int MODE_SCROLLABLE 可滚动选项卡在任何给定时刻只显示一部分选项卡,并且可以包含更长的选项卡标签和更多选项卡。当用户不需要直接比较选项卡标签时,在触摸界面中浏览上下文时最好使用它们。

因此 GRAVITY_FILL 仅与 MODE_FIXED 兼容,但是由于没有指定 GRAVITY_CENTER 的情况下,我期望它与 MODE_SCROLLABLE 兼容,但是这是我在使用 GRAVITY_CENTER 和 MODE_SCROLLABLE 时看到的结果:

enter image description here

因此,在两个方向上都使用了 SCROLLABLE,但未使用 GRAVITY_CENTER。

这是我期望的横向布局;但是要实现这一点,我需要设置 MODE_FIXED,因此在纵向布局中得到以下结果:

enter image description here

如果 TabLayout 可以适应屏幕大小,为什么 GRAVITY_CENTER 不起作用?有没有办法动态设置重力和模式(并查看我期望的效果)?

非常感谢!

编辑:这是我的 TabLayout 布局:

<android.support.design.widget.TabLayout
    android:id="@+id/sliding_tabs"
    android:layout_width="match_parent"
    android:background="@color/orange_pager"
    android:layout_height="wrap_content" />

@Fighter42,你找到解决办法了吗?我也遇到了同样的问题。 - Akhil
我找到的唯一方法是手动获取选项卡的大小,然后根据其是否适合动态配置布局参数。 - Javier Delgado
@Fighter42,你能发一些你正在使用的解决方案的示例代码吗? - Sammys
1
我知道我的答案在逻辑上不是很好,但它对我有帮助。在文本前后加上一些空格,这样它就可以在两种模式下滚动。 - AmmY
16个回答

2

非常简单的例子,而且它总是有效的。


/**
 * Setup stretch and scrollable TabLayout.
 * The TabLayout initial parameters in layout must be:
 * android:layout_width="wrap_content"
 * app:tabMaxWidth="0dp"
 * app:tabGravity="fill"
 * app:tabMode="fixed"
 *
 * @param context   your Context
 * @param tabLayout your TabLayout
 */
public static void setupStretchTabLayout(Context context, TabLayout tabLayout) {
    tabLayout.post(() -> {

        ViewGroup.LayoutParams params = tabLayout.getLayoutParams();
        if (params.width == ViewGroup.LayoutParams.MATCH_PARENT) { // is already set up for stretch
            return;
        }

        int deviceWidth = context.getResources()
                                 .getDisplayMetrics().widthPixels;

        if (tabLayout.getWidth() < deviceWidth) {
            tabLayout.setTabMode(TabLayout.MODE_FIXED);
            params.width = ViewGroup.LayoutParams.MATCH_PARENT;
        } else {
            tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
            params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
        }
        tabLayout.setLayoutParams(params);

    });

}

谢谢你的建议。稍微根据我的情况做了一点改变,现在完美运作。 - Eren Tüfekçi

1

你只需要将以下内容添加到你的TabLayout中即可

custom:tabGravity="fill"

So then you'll have:

xmlns:custom="http://schemas.android.com/apk/res-auto"
<android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        custom:tabGravity="fill"
        />

这不是创建者所要求的。问题在于选项卡永远不会可滚动,而且屏幕上的空间会被消耗掉。选项卡将开始缩小其文本,最终它们将变成两行。 - Sotti

1
if(tabLayout_chemistCategory.getTabCount()<4)
    {
        tabLayout_chemistCategory.setTabGravity(TabLayout.GRAVITY_FILL);
    }else
    {
        tabLayout_chemistCategory.setTabMode(TabLayout.MODE_SCROLLABLE);

    }

1
class DynamicModeTabLayout : TabLayout {
 
    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    override fun setupWithViewPager(viewPager: ViewPager?) {
        super.setupWithViewPager(viewPager)

        val view = getChildAt(0) ?: return
        view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
        val size = view.measuredWidth

        if (size > measuredWidth) {
            tabMode = MODE_SCROLLABLE
            tabGravity = GRAVITY_CENTER
        } else {
            tabMode = MODE_FIXED
            tabGravity = GRAVITY_FILL
        }
    }
}

0

Sotti的解决方案非常好!它正好像应该工作的基础组件一样。

在我的情况下,选项卡可以根据筛选条件动态演变,因此我进行了小的调整,以允许使用redraw()方法更新选项卡模式。它也是用Kotlin编写的。

class AdaptiveTabLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : TabLayout(context, attrs, defStyleAttr) {
    private var gravityAndModeSeUpNeeded = true

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        super.onLayout(changed, l, t, r, b)
        if (gravityAndModeSeUpNeeded) {
            setModeAndGravity()
        }
    }

    fun redraw() {
        post {
            tabMode = MODE_SCROLLABLE
            gravityAndModeSeUpNeeded = true
            invalidate()
        }
    }

    private fun setModeAndGravity() {
        val tabCount = tabCount
        val screenWidth = Utils.getScreenWidth()
        val minWidthNeedForMixedMode = getMinSpaceNeededForFixedMode(tabCount)
        if (minWidthNeedForMixedMode == 0) {
            return
        } else if (minWidthNeedForMixedMode < screenWidth) {
            tabMode = MODE_FIXED
            tabGravity = if (Utils.isBigTablet()) GRAVITY_CENTER else GRAVITY_FILL
        } else {
            tabMode = MODE_SCROLLABLE
        }
        gravityAndModeSeUpNeeded = false
    }

    private fun getMinSpaceNeededForFixedMode(tabCount: Int): Int {
        val linearLayout = getChildAt(0) as LinearLayout
        var widestTab = 0
        var currentWidth: Int
        for (i in 0 until tabCount) {
            currentWidth = linearLayout.getChildAt(i).width
            if (currentWidth == 0) return 0
            if (currentWidth > widestTab) {
                widestTab = currentWidth
            }
        }
        return widestTab * tabCount
    }

    init {
        tabMode = MODE_SCROLLABLE
    }
}

0
在TabLayout中添加选项卡时,请将此行添加到您的活动中。
 tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); 

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