让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,但它没有填满整个屏幕。
初步想法
- 我将您的布局复制并粘贴到 Android Studio 4.x,将所有 @string 引用替换为“某物”,将所有 @drawable 替换为现有的(来自
@android:drawable/
)所以我的布局会呈现。
据我所见,它看起来是正确的:
- 我注意到您的布局中存在一些不一致。
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 一切都说完了才能应用边距(这就是它的方式作品)。
好吧,咆哮够了 - 你能做什么?
我会通过添加正确的约束来“修复”布局,并且 - 如果需要 - 对所有小部件使用 VerticalChain 和偏置。
我会通过将 textview 和 imageView 包装在 ConstraintLayout 中来修复中间 (Cardview 2) 内容。
我会删除 left/right
并替换为 start/end
(除非您的目标是 API 16 或以下)。
我将 ViewPager 在两个维度上都设置为 0dp。
你的 CardView2 的 children 指的是 copyButton
和 favoriteButton
但这些在你粘贴的布局中不存在,所以我假设你有那里有更多按钮)。
完整版(已修改)
如果您想知道,这就是我所做的(我为 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>
我有以下 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,但它没有填满整个屏幕。
初步想法
- 我将您的布局复制并粘贴到 Android Studio 4.x,将所有 @string 引用替换为“某物”,将所有 @drawable 替换为现有的(来自
@android:drawable/
)所以我的布局会呈现。
据我所见,它看起来是正确的:
- 我注意到您的布局中存在一些不一致。
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 一切都说完了才能应用边距(这就是它的方式作品)。
好吧,咆哮够了 - 你能做什么?
我会通过添加正确的约束来“修复”布局,并且 - 如果需要 - 对所有小部件使用 VerticalChain 和偏置。
我会通过将 textview 和 imageView 包装在 ConstraintLayout 中来修复中间 (Cardview 2) 内容。
我会删除
left/right
并替换为start/end
(除非您的目标是 API 16 或以下)。我将 ViewPager 在两个维度上都设置为 0dp。
你的 CardView2 的 children 指的是
copyButton
和favoriteButton
但这些在你粘贴的布局中不存在,所以我假设你有那里有更多按钮)。
完整版(已修改)
如果您想知道,这就是我所做的(我为 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>