ViewPager 的非同级约束在其选项卡下方,其中 TabLayout 在 AppbarLayout 中,而 ViewPager 在 DrawerLayout 中

Nonsibling Constraint for a ViewPager BELOW its Tabs, where TabLayout in AppbarLayout, and ViewPager in a DrawerLayout

我有一个主要的 activity ConstraintLayout,它需要在顶部 AppbarLayout 下方可见的区域中显示 ViewPager LiveData,其中包含 ViewPager 的滚动 TabLayout 项目名称。我的困难是 ViewPager 片段文本的顶部被 AppbarLayout 工具栏和选项卡遮挡了。我正在尝试将 ViewPager 数据限制为显示在 AppbarLayout 区域下方。

我可以像在 AS 附带的 TabLayout activity 模板中那样做,当 TabLayout 单独存在时它可以按需要工作。不幸的是,我的 Activity 也迎合了 DrawerLayout NavigationView 菜单,而 Drawer 和 ViewPager 交替响应滑动的唯一方式是当我将 ViewPager 嵌套在 DrawerLayout 中,放在它的 NavigationView 之前。所以我的 ViewPager 已经关闭在 XML 规范底部的 ActivityLayout 中的 DrawerLayout 中:

<ConstraintLayout
        ...
    <androidx.drawerlayout.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:openDrawer="start"
        app:layout_constraintTop_toBottomOf="@+id/cal_appbar">
    <androidx.viewpager.widget.ViewPager
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:focusableInTouchMode="true"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:visibility="visible">
        </androidx.viewpager.widget.ViewPager>

        <com.google.android.material.navigation.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:fitsSystemWindows="true"
            app:headerLayout="@layout/nav_header_refresh"
            app:menu="@menu/activity_calib_drawer" />

    </androidx.drawerlayout.widget.DrawerLayout>
</ConstraintLayout>

在它和我用省略号显示的根标记之间,ConstraintLayout 有一个 AppbarLayout,包含 Toolbar 和 TabLayout,后面是用于其他 Fragment 的 RelativeLayout。该问题不涉及 RelativeLayout,而是 AppbarLayout 与 ViewPager 的显示重叠

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:fitsSystemWindows="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/cal_appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay"
        android:fitsSystemWindows="true"
        tools:context=".Calibsense"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/cal_toolbar"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/actionBarSize"
            android:background="@color/colorPrimary"
            android:visibility="visible"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/AppTheme.PopupOverlay" >

            <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:minHeight="?actionBarSize"
                android:padding="@dimen/appbar_padding_top"
                android:text="@string/intro_name"
                android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"/>
        </androidx.appcompat.widget.Toolbar>

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:visibility="visible"
            app:layout_constraintTop_toBottomOf="@id/cal_appbar">
        </com.google.android.material.tabs.TabLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/overlap">
        ...

    </RelativeLayout>
    ...
</ConstraintLayout>

ConstraintLayout 坚持约束兄弟姐妹,所以我上面的约束指定包含针对 AppbarLayout 约束的视图 DrawerLayout 而不是最终目标:针对 TabLayout 的 ViewPager。

是否有可用于指定片段 (ViewPager) 显示在 AppbarLayout-TabLayout 下方的启发式约束?

作为一种可能的解决方法,有没有一种方法可以为 ViewPager 指定一个顶部填充,其高度为 AppbarLayout,以将其内容推送到可视区域?

我也研究过尝试使用 CollapsingToolbarLayout,但设法显示整个 ViewPager 完全没有 AppBarLayout。

附录:

在 Activity 的 onCreate() 方法调用 setGuide() 期间,进一步查看上面的编程调用,我在下面公开了 AppbarLayout 参数,调试器向我显示了与 XML设置:高度-1(match_parent)和宽度-2(wrap_content),在setGuide()末尾用子视图展开后该值保持不变。 measuredHeight 始终显示值为零。我不知道这些值的意义;我希望看到几何值,例如非零 px / dp 数量。任何人都可以阐明一下吗? measuredHeight 为零是否也意味着 ViewPager 被锚定在 px (0,0),如果是这样,如何将锚点 y 值更改为低于 AppbarLayout 的可见底部?但我需要先以编程方式提取该值。如何实现?

DrawerLayout drwLyt;
SectionsPagerAdapter sectionsPagerAdapter;
ViewPager viewPager;
AppBarLayout aBL;
CollapsingToolbarLayout cTBL;
TabLayout tabs;
TextView title;
ConstraintLayout mainGuideView;
Calibsense guideParent;

void setGuide(Calibsense guideModule){
    guideParent = guideModule;
    // AppbarLayout
    aBL = guideParent.findViewById(R.id.cal_appbar);
    ViewGroup.LayoutParams aBLParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    aBL.setLayoutParams(aBLParams);
    aBL.setExpanded(true);
    // measure AppbarLayout using params copy of internal value
    ViewGroup.LayoutParams appBarLayoutParams = aBL.getLayoutParams();
    int aBLHeight = appBarLayoutParams.height;
    int aBLmHeight =  aBL.getMeasuredHeight();

    drwLyt =  findViewById(R.id.drawer_layout);
    ViewGroup.LayoutParams drawerLayoutParams = drwLyt.getLayoutParams();
    int drwLytHeight = drawerLayoutParams.height;

    // setting-up of viewPager
    sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
    viewPager = findViewById(R.id.view_pager);
    // this could be redundant,
    // somewhere it was suggested a new LayoutParams() is required
    ViewGroup.LayoutParams viewPagerParams = viewPager.getLayoutParams();
    viewPager.setAdapter(sectionsPagerAdapter);
    int viewPagerHeight = viewPager.getHeight();

    View spacerView = findViewById(R.id.pager_spacer);
    int spacerHeight = spacerView.getHeight();
    spacerView.setMinimumHeight(aBLHeight);
    // Start set-up of tabs
    TabLayout tabs = findViewById(R.id.tabs);

    // complete set-up of tabs by insertion of viewPager
    tabs.setupWithViewPager(viewPager);
    int tabsHeight = tabs.getHeight();
    relL.setVisibility(View.INVISIBLE);
    // measure AppbarLayout using params copy of internal value
    appBarLayoutParams = aBL.getLayoutParams();
    aBLHeight = appBarLayoutParams.height;
    aBLmHeight =  aBL.getMeasuredHeight();
}

好像是规​​格:

android:fitsSystemWindows="true"

覆盖其他约束并将可视项目锚定在 (0,0),但我不清楚该覆盖的范围和范围,所以我现在暂时避免使用它。

此外,经过许多trials-and-error(包括对 hide/show SystemUI 和 decorView Insets 等的一些失误),这个微妙问题的解决方案在于这个微妙之处:

为了toolbar显示在内容之上,最后声明,为了ViewPager内容不被systemDecor遮挡,先声明。 因此 xml 标签 macro-code 中的当前解决方案是:

<CoordinatorLayout>
   <DrawerLayout>
   <ViewPager>...</ViewPager>
   <RelativeLayout>...</RelativeLayout>
   <AppBarLayout>
      <TabLayout>...</TabLayout>
   </AppBarLayout>
   <ToolBar/>
   <NavigationView/>
   </DrawerLayout>
</CoordinatorLayout>

然后所有组件的行为都与宣传的一样(除了 TabLayout 不公开其最后一个页面标题)。 简单的问题需要简单的解决方案,而不是深入研究 API 内部结构!