Android 我们如何为固定数量的可滚动选项卡配置TabLayout?

Android 我们如何为固定数量的可滚动选项卡配置TabLayout?,android,material-components-android,Android,Material Components Android,在一个项目中,我们使用了材质设计组件的TabLayout和ViewPager。共有14个选项卡,我们希望其中7个选项卡在表格布局中一次可见。标签内容足够窄,我们确信7个标签不会太多,设计团队希望无论屏幕宽度如何,都能显示一致数量的标签(标签代表一周中的几天) 所有预定义的选项卡模式似乎都与此不匹配: MODE\u FIXED和MODE\u AUTO控制可见选项卡的数量。。。通过展示所有这些 MODE\u SCROLLABLE允许选项卡滚动。。。但是,我们无法控制可见选项卡的数量 有没有一种不

在一个项目中,我们使用了材质设计组件的
TabLayout
ViewPager
。共有14个选项卡,我们希望其中7个选项卡在
表格布局中一次可见。标签内容足够窄,我们确信7个标签不会太多,设计团队希望无论屏幕宽度如何,都能显示一致数量的标签(标签代表一周中的几天)

所有预定义的选项卡模式似乎都与此不匹配:

  • MODE\u FIXED
    MODE\u AUTO
    控制可见选项卡的数量。。。通过展示所有这些
  • MODE\u SCROLLABLE
    允许选项卡滚动。。。但是,我们无法控制可见选项卡的数量
有没有一种不涉及不可维护的黑客的方法来实现这一点,比如在运行时使用反射来修补
tabPaddingStart
,或者迭代选项卡小部件并调整它们的
LayoutParams


我已经看到了,但缺乏解释——特别是,不清楚如何使用
app:tabMaxWidth
在运行时作为动态值。另外,这个问题与旧的设计支持库有关,它可能与MDC的实现有所不同

我也必须这样做,我特别注意地调查了这个问题。剧透:我失败了-目前你想通过股票
TabLayout
和干净的Android方式实现的目标是不可能的

不过也有黑客)

  • 最合适的方法是使用允许这样做的库-例如

  • 尽管您提到了这一点,但不想这样做-迭代
    TabLayout
    子对象更改其
    LayoutParams
    是下一个适当的方法。该方法利用Android提供的公共方法,不需要使用一些不太好的技术。说到这里

*反射开始
  • 更改
    tabPaddingStart
    requestedTabMinWidth
    以及
    requestedTabMaxWidth
    。这很糟糕。我甚至不想开始解释为什么。这是这个列表中最不合适的一种方式。不过,这仍然是一种解决问题的方法

  • 这是干净的Android方式和
    TabLayout
    参数
    app:tabMaxWidth
    app:tabMinWidth
    以及反射的组合。在这种情况下,反射有点不同-它几乎是正常的(尽可能多的反射)。我建议在
    integers.xml
    中创建一个名为
    tabWidth
    integer
    android资源(我相信您已经知道我要去哪里了),在应用程序启动时,您可以通过反射将其替换为
    screenWidth
    的值除以7(或更小,取决于填充)

*反光饰面
  • 还有一种方法,它是Android clean,但仍然非常不足。您可以组合使用
    查看页面
    和/或片段。最简单的是一个
    ViewPager
    ,其中有两个
    ViewPager
    s和两个
    TabLayout
    s,每个都有7个页面和7个选项卡。不过,您可能需要调整手势处理程序。还有更多的组合
我将不包括您在
RecyclerView
SnapHelper
的帮助下自己编写
TabLayout
的方法,因为在Android中自己编写东西总是一种选择。。。浪费大量的时间

我知道这不是一个答案。此外,这是一个如何在Android中不做事情的列表,但有时我们需要选择黑暗面


希望能有所帮助。

有几种方法可以显示固定数量的选项卡,而不考虑屏幕宽度,但所需的功能确实被锁定了。最值得注意的是,如果TabLayout中的getTabMinWidth()不是私有的,那么一个简单的解决方案就是在自定义TabLayout视图中重写该方法

下面是Eugen Pechanec在上面的评论中建议的内容,其中包括选项卡的自定义视图

首先是基地布局

活动\u main.xml

<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@android:id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Tab x"
        android:textAppearance="@style/TextAppearance.AppCompat.Body2" />

<!--    If an icon is needed. -->
<!--    <ImageView-->
<!--        android:id="@android:id/icon"-->
<!--        android:layout_width="48dp"-->
<!--        android:layout_height="48dp"-->
<!--        android:scaleType="centerCrop"-->
<!--        android:src="@drawable/ic_launcher_foreground" />-->
</LinearLayout>
tabMinWidth
tabpaddingnd
tabPaddingStart
都设置为
0dp
tabMinWidth
的默认值可能太大,无法满足我们的需要。填充可以设置为非零,但我更愿意在选项卡的自定义视图中处理

ViewPager没有发生任何事情


至少在
材料:1.1.0-beta01
中,有一个
选项卡minwidth
XML属性用于
表格布局
。您可以将其与自定义选项卡视图(
tab.setCustomView(视图)
)结合使用。您必须在创建选项卡时知道所需的宽度,或者在选项卡间迭代,然后更新每个视图。@EugenPechanec:不过,我不知道如何在运行时使用
tabMinWidth
。我们不知道编译时屏幕宽度的1/7是多少(至少是
dp
维度)。啊,我的错误。我将
tabMinWidth
设置为零。然后,选项卡中的自定义视图将有足够的腿部空间,使其尽可能小。其中一个问题是可滚动选项卡的默认最小宽度为72dp。第一步,将其置为零,这就是我们所做的。非常感谢您的详细写作!
<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@android:id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Tab x"
        android:textAppearance="@style/TextAppearance.AppCompat.Body2" />

<!--    If an icon is needed. -->
<!--    <ImageView-->
<!--        android:id="@android:id/icon"-->
<!--        android:layout_width="48dp"-->
<!--        android:layout_height="48dp"-->
<!--        android:scaleType="centerCrop"-->
<!--        android:src="@drawable/ic_launcher_foreground" />-->
</LinearLayout>
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val tabLayout = findViewById<TabLayout>(R.id.tabs)
        tabLayout.doOnLayout {
            val tabWidth = tabLayout.width / 7
            for (i in 1..14) {
                tabLayout.newTab().run {
                    setCustomView(R.layout.custom_tab)
                    customView?.minimumWidth = tabWidth
                    setText("Tab $i")
                    tabLayout.addTab(this)
                }
            }
        }

    }
}