如何让 ScrollView 填充其父级剩余的 space 的其余部分?

How can I make a ScrollView fill the rest of its parent's remaining space?

我有两个 TextView 和一个 ScrollView 嵌套在 ConstraintLayout 中。在 ScrollView 里面有一个 TableLayout。 ScrollView 的左、右和底部约束设置为“parent”。顶部约束设置为它之前的 TextView。这是 XML:

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:text="TextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textSize="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView6">

        <TableLayout
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:layout_marginStart="32dp"
            android:layout_marginTop="32dp"
            android:layout_marginEnd="32dp"
            android:layout_marginBottom="32dp"
            android:gravity="center"
            android:stretchColumns="0,1,2,3,4">

            <TableRow
                android:layout_width="fill_parent"
                android:layout_weight="1">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="1" />
                    ... 4 more TextViews
            </TableRow>
            ... many more TableRows
        </TableLayout>
    </ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

问题是 ScrollView 的宽度与其约束不匹配。相反,当添加更多行使得 ScrollView 高于其父级的剩余高度时,它会与它之前的 TextView 重叠。下面两个截图说明了问题:

无重叠:

重叠:

当我将 ScrollView 高度设置为“0dp”(匹配约束)时,它按字面意思呈现为 0dp(ScrollView 缩小并显示其内容的 none)。

我应该更改什么以使 ScrollView 扩展并填充其父容器的剩余高度?

您需要正确约束 ConstraintLayout 的小部件,以便能够正确测量和布置您的视图。

简而言之:

  1. Top TextView需要是垂直链的头部(app:layout_constraintVertical_chainStyle="packed"),并且必须有底部约束(bottom_to_Topof...):
    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:text="TextView"
        app:layout_constrainedHeight="true"
        app:layout_constraintVertical_chainStyle="packed"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/textView6" />

textView 是 constrainedHeight = true,因为您希望它 wrap_content,并且具有文本的小部件在约束布局中包装时可能会出现一些问题(有关更多信息,请参阅 为什么可能需要这样做)。

第二个 TextView 也需要固定到某个底部,在本例中是 scrollView...

    <TextView
        android:id="@+id/textView6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constrainedHeight="true"
        android:text="TextView"
        android:textSize="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2"
        app:layout_constraintBottom_toTopOf="@id/scrollView" />

现在它们链接在一起,但 ScrollView 需要一些操作...

只需将滚动视图固定在底部,这样它就可以从某个地方拉动,并给它你需要的 0dp,这样它就可以根据约束计算它的 size/position。

<ScrollView
        android:id="@+id/scrollView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView6">

(也给它一个 name/id...)

这会导致 CL 正确计算 space/sizing 并避免您抱怨的重叠,因为它现在有关于什么可以去哪里的明确规则。

当您省略约束(如 bottom)时,尤其是当周围有像 ScrollViews 这样愚蠢的小部件时,您可能会根据内容产生不可预知的行为,这是很难做到的预期和修复。始终,如有疑问,请尝试为所有小部件提供所有可能的约束。

我会提出几点建议(我不知道哪一个是关键):

1.您不应该对 ConstraintLayout 的子视图使用 match_parent。相反,请使用“0dp”。

Official training:

Note: You cannot use match_parent for any view in a ConstraintLayout. Instead use "match constraints" (0dp).

2。您不应该使用 @+id/xxx 而是使用 @id/xxx 指定其他视图。 前者用于创建新 ID。

  1. 将 ConstraintLayout 的 layout_height 更改为 match_parent

  2. 将 TableLayout 的 layout_height 更改为 wrap_content

我的结果:

layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="bottom">

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginEnd="16dp"
            android:text="TextView"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/textView6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TextView"
            android:textSize="16dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/textView2" />

        <ScrollView
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/textView6">

            <TableLayout
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="32dp"
                android:layout_marginTop="32dp"
                android:layout_marginEnd="32dp"
                android:layout_marginBottom="32dp"
                android:gravity="center"
                android:stretchColumns="0,1,2,3,4">

                <TableRow
                    android:layout_width="fill_parent"
                    android:layout_weight="1">

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:text="1" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:text="2" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:text="3" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:text="4" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:text="5" />
                </TableRow>

               <!-- plenty of TableRows... -->

            </TableLayout>
        </ScrollView>
    </androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>