让ViewPager填充一个ConstraintLayout中剩余的Space

Make ViewPager Fill The Remaining Space In a ConstraintLayout

我有以下 XML 代码,我无法让 'summaryViewPager' 垂直填充剩余的 space,直到屏幕底部:

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

        <com.google.android.material.card.MaterialCardView
            android:id="@+id/mainCardView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"
            android:layout_marginEnd="10dp"
            android:layout_marginRight="10dp"
            android:background="#666266"
            android:padding="10dp"
            app:cardCornerRadius="20dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

                <TextView
                    android:id="@+id/textView"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="3dp"
                    android:layout_marginLeft="3dp"
                    android:layout_marginTop="2dp"
                    android:text="@string/category"
                    android:textColor="#FFBA93"
                    android:textSize="20sp"
                    android:textStyle="bold"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
        </com.google.android.material.card.MaterialCardView>

        <com.google.android.material.card.MaterialCardView
            android:id="@+id/cardView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"
            android:layout_marginEnd="10dp"
            android:layout_marginRight="10dp"
            android:background="#666266"
            android:padding="10dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/mainCardView">


                <Button
                    android:id="@+id/shareButton"
                    android:layout_width="30dp"
                    android:layout_height="30dp"
                    android:layout_marginStart="5dp"
                    android:layout_marginLeft="5dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginEnd="5dp"
                    android:layout_marginRight="5dp"
                    android:background="@drawable/ic_share"
                    app:layout_constraintEnd_toStartOf="@+id/copyButton"
                    app:layout_constraintHorizontal_bias="0.5"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />


                <ImageView
                    android:id="@+id/seenImageView"
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_marginStart="3dp"
                    android:layout_marginLeft="3dp"
                    android:layout_marginTop="15dp"
                    android:layout_marginEnd="5dp"
                    android:layout_marginRight="5dp"
                    android:contentDescription="@string/todo"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.5"
                    app:layout_constraintStart_toEndOf="@+id/favoriteButton"
                    app:layout_constraintTop_toTopOf="parent"
                    app:srcCompat="@drawable/unseen" />
        </com.google.android.material.card.MaterialCardView>

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/summaryViewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="2dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/cardView2" />

    </androidx.constraintlayout.widget.ConstraintLayout>

上面的代码在 cardView2 下面根本没有显示 PageViewer,但是当我设置 android:layout_height="500dp 它确实显示了 PageViewer,但它没有填满整个屏幕。

初步想法

  1. 我将您的布局复制并粘贴到 Android Studio 4.x,将所有 @string 引用替换为“某物”,将所有 @drawable 替换为现有的(来自 @android:drawable/)所以我的布局会呈现。

据我所见,它看起来是正确的:

  1. 我注意到您的布局中存在一些不一致

CardView 编号 1(顶部)

  • 小心 CardView 上的填充(不知道你的 min/max API 所以,不确定这是否适用于你)。
  • 您的 CardView 对其 BOTTOM 没有任何限制,它保留为“包装后计算的任何大小”(高度 = 包装,Bottom_To = null)。
  • 这 ^ 意味着要使 CardView 具有高度,其所有内部小部件都必须计算它们的大小,因此顶部卡片视图知道它需要多少大小 + 边距 + 填充。它不依赖于其他小部件(不是 children),因为它的约束全部针对 parent。 (相反,它只需要 parent)。

CardView 编号 2(底部)

  • 这个 cardView 包裹了它的所有尺寸,但与上面那个有同样的问题,它不限制它的高度(除了被固定在前一个 CardView 1 的底部)。同样,这很好,只要没有人依赖它(这是不正确的)。这个必须等待更多的小部件才能知道它的大小,因为它必须等待 CardView1 才能知道还剩下多少 space,并且还需要知道它的 children 需要多少。这并不难,因为两者(ImageView 和 Button)都有固定大小(分别为 20 和 30 dp)+ margins/padding.
  • MaterialCardView children cannot/should not/must 不使用 constraints 因为 CardView 不是 ConstraintLayout,而是美化的 FrameLayout,它只能容纳一个child(或者如果它有更多,它会将它们放在另一个之上)。所以所有这些约束(对于 shareButton 和 seenImageView)都被忽略了。
  • 解决上述问题的方法是,将内部 ConstraintLayout 作为 CardView 的 sole child,并在此 inner CL,把你所有的children和他们的约束。内部 ConstraintLayout 应该将其 width/height 作为 wrap_content 或 match_parent,以便它们使用 parent 的约束。由于它们具有固定大小,因此这不是问题。 (如果他们不这样做,那将不会是 问题 ,但需要另一个措施通过)。
  • 无论如何,这第二个 CardView 能够计算出它的高度,因为它的 children 报告的大小为 20+30(重叠)+ 15 边距顶部(图像)所以..所有这些合并后的高度可能是 45dp~(因为它们仅重叠最大数字适用于此)。
  • 这两个 children.
  • 忽略所有约束

ViewPager(底部)

终于到了 VPager。这个 viewPager 的宽度是 match_parent(因为你对 start/end 有限制,你应该只使用 0dp)。它的高度为 wrap_content

  • layout_height=wrap_content -> 这是这里的问题。因为 viewPager(在布局 pass/measure 时)还不知道它的内容是什么。所以你可能希望这是 0dp 并让 ViewPager 在计算完上面的内容后使用所有可用的 space。

  • 你这里的marginTop不会按原样工作,因为CardView 1和2没有bottom constrain,所以这个必须创建 yet another layout/measure pass after 一切都说完了才能应用边距(这就是它的方式作品)。

好吧,咆哮够了 - 你能做什么?

  1. 我会通过添加正确的约束来“修复”布局,并且 - 如果需要 - 对所有小部件使用 VerticalChain 和偏置。

  2. 我会通过将 textview 和 imageView 包装在 ConstraintLayout 中来修复中间 (Cardview 2) 内容。

  3. 我会删除 left/right 并替换为 start/end(除非您的目标是 API 16 或以下)。

  4. 我将 ViewPager 在两个维度上都设置为 0dp。

  5. 你的 CardView2 的 children 指的是 copyButtonfavoriteButton 但这些在你粘贴的布局中不存在,所以我假设你有那里有更多按钮)。

完整版(已修改)

如果您想知道,这就是我所做的(我为 VP 的背景添加了一种颜色,以便更容易“看到”)。

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

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/mainCardView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="10dp"
        app:layout_constraintVertical_chainStyle="packed"
        android:background="#666266"
        android:padding="10dp"
        app:cardCornerRadius="20dp"
        app:layout_constraintBottom_toTopOf="@id/cardView2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="3dp"
            android:layout_marginTop="2dp"
            android:text="Category"
            android:textColor="#FFBA93"
            android:textSize="20sp"
            android:textStyle="bold" />
    </com.google.android.material.card.MaterialCardView>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/cardView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="10dp"
        android:layout_marginRight="10dp"
        android:background="#666266"
        android:padding="10dp"
        app:layout_constraintBottom_toTopOf="@id/summaryViewPager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/mainCardView">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/innerCardView2Root"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Button
                android:id="@+id/shareButton"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_marginStart="5dp"
                android:layout_marginTop="8dp"
                android:layout_marginEnd="5dp"
                android:background="@android:drawable/ic_menu_share"
                app:layout_constraintEnd_toStartOf="@+id/seenImageView"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />


            <ImageView
                android:id="@+id/seenImageView"
                android:layout_width="20dp"
                android:layout_height="20dp"
                android:layout_marginStart="3dp"
                android:layout_marginTop="15dp"
                android:layout_marginEnd="5dp"
                android:contentDescription="@null"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/shareButton"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@android:drawable/ic_menu_search" />
        </androidx.constraintlayout.widget.ConstraintLayout>

    </com.google.android.material.card.MaterialCardView>

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/summaryViewPager"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="2dp"
        android:background="@color/colorSecondary"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/cardView2" />

</androidx.constraintlayout.widget.ConstraintLayout>