在 Android Kotlin 的约束布局中设置适当的约束

Posted

技术标签:

【中文标题】在 Android Kotlin 的约束布局中设置适当的约束【英文标题】:Set proper constraint in Constraint Layout in Android Kotlin 【发布时间】:2021-12-23 08:33:16 【问题描述】:

我正在创建一个聊天应用程序。我使用 stackFromEnd = falsereverseLayout = true 从屏幕底部显示项目。我在其中使用了 reyclerview,它工作正常,我在下面添加了带有屏幕截图的代码。长什么样子

<?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_
    android:layout_
    android:background="#cccccc">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/conversationRecyclerView"
        android:layout_
        android:layout_
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:paddingBottom="10dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0" />

</androidx.constraintlayout.widget.ConstraintLayout>

当 recyclerView 中有一个项目时,上面的代码可以正常工作,它会打开这样的屏幕

图片 1

但是当有更多项目时,屏幕看起来像这样

图片 2

Note: This above image is my expected output. Also soft keyboard shift the layout.

现在主要故事开始了,我想在屏幕底部添加editText。

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:background="#cccccc">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/conversationRecyclerView"
        android:layout_
        android:layout_
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:paddingBottom="10dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toTopOf="@+id/inputContainer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/inputContainer"
        android:layout_
        android:layout_
        android:background="#ffffff"
        android:paddingStart="10dp"
        android:paddingTop="14dp"
        android:visibility="gone"
        android:paddingEnd="10dp"
        android:paddingBottom="14dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/conversationRecyclerView"
        app:layout_constraintVertical_bias="1.0">

        <EditText
            android:id="@+id/edittext"
            android:layout_
            android:layout_
            android:inputType="textMultiLine|text|textNoSuggestions"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

问题 1

图片 1 没有得到正确的约束,看起来像这样

image 2 工作正常,软键盘改变了布局。

问题 2

我尝试了一些代码来解决问题1并且软键盘没有改变布局

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:background="#cccccc">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/conversationRecyclerView"
        android:layout_
        android:layout_
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:paddingBottom="10dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constrainedHeight="true"
        app:layout_constraintBottom_toTopOf="@+id/inputContainer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/inputContainer"
        android:layout_
        android:layout_
        android:background="#ffffff"
        android:paddingStart="10dp"
        android:paddingTop="14dp"
        android:paddingEnd="10dp"
        android:paddingBottom="14dp"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintVertical_bias="1.0">

        <EditText
            android:id="@+id/sendMessageEditText"
            android:layout_
            android:layout_
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

更新

在@Cheticamp 建议之后,我添加了这个但没有工作。它还有一个问题1问题。解决不了。

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:background="#cccccc">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/conversationRecyclerView"
        android:layout_
        android:layout_
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:paddingBottom="10dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constrainedHeight="true"
        app:layout_constraintBottom_toTopOf="@+id/inputContainer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
         />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/inputContainer"
        android:layout_
        android:layout_
        android:background="#ffffff"
        android:paddingStart="10dp"
        android:paddingTop="14dp"
        android:paddingEnd="10dp"
        android:paddingBottom="14dp"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
      >

        <EditText
            android:id="@+id/sendMessageEditText"
            android:layout_
            android:layout_
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

更新 1

在@Tenfour04 的建议之后,我添加了一些代码,请看一下。我做得对吗?

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:background="#cccccc">

    <FrameLayout
        android:id="@+id/conversationRecyclerViewViewWrapper"
        android:layout_
        android:layout_
        app:layout_constraintBottom_toTopOf="@+id/inputContainer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/conversationRecyclerView"
            android:layout_
            android:layout_
            android:layout_gravity="top"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:paddingBottom="10dp"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

    </FrameLayout>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/inputContainer"
        android:layout_
        android:layout_
        android:background="#ffffff"
        android:paddingStart="10dp"
        android:paddingTop="14dp"
        android:paddingEnd="10dp"
        android:paddingBottom="14dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/conversationRecyclerView">

        <EditText
            android:id="@+id/sendMessageEditText"
            android:layout_
            android:layout_
            android:inputType="textMultiLine|text|textNoSuggestions"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

【问题讨论】:

【参考方案1】:

问题是您的 RecyclerView 的高度是 wrap_content 而不是 0dp(又名“match_constraints”),因此它忽略了它应该高于 inputContainer 的约束。

因此,与其将其设为wrap_content 并使用垂直偏差来尝试将其保持在屏幕顶部,不如尝试将其包装在 FrameLayout 中并赋予其“顶部”的布局重力。 FrameLayout 应该使用 0dp 作为高度,以便它可以填充整个空间,但不能重叠inputContainer。 RecyclerView 可以使用wrap_content 作为高度,布局重力会将其偏向FrameLayout 空间的顶部。所以用这个替换你的 RecyclerView 元素:

<FrameLayout
    android:id="@+id/recyclerViewWrapper"
    android:layout_
    android:layout_
    app:layout_constraintBottom_toTopOf="@+id/inputContainer"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/conversationRecyclerView"
        android:layout_
        android:layout_
        android:layout_gravity="top"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:paddingBottom="10dp"
        app:layoutManager="LinearLayoutManager"
        app:reverseLayout="true"/>
</FrameLayout>

app:layout_constraintVertical_biasinputContainer 上毫无意义,因为它没有顶部约束,因此您可以删除它。

【讨论】:

再次感谢您对我的帮助。我正在尝试你的代码。我需要向app:layout_constraintTop_toBottomOf="@+id/conversationRecyclerView"in inputContainer 提出一个问题吗? 我在 UPDATE 1 中添加代码,请看一下。谢谢一百万。 这没有意义,而且我认为不支持将 inputContainer 顶部约束到不是 ConstraintLayout 的直接子视图的视图。如果我理解正确,您只希望 inputContainer 偏向屏幕底部,因此您不需要限制其顶部。无论如何它都是多余的,因为 FrameLayout 的底部已经被限制在 inputContainer 的顶部。 感谢@Tenfour04 为您提供解决方案。 你能看看这个issue【参考方案2】:

对于问题 #1,将 RecyclerView 的高度和宽度设为0dp 并让约束调整其大小以填满屏幕。另外,消除垂直偏差 - 你不需要它。

顺便说一句,永远不要在 ConstraintLayout 中使用match_parent。始终使用0dp 和约束。

这可能会解决您使用此布局的所有问题。

更新:我应该在你的布局中向下滚动。

我认为您希望 RecyclerView 填满屏幕,底部的 EditText 除外。一般来说,ConstraintLayout 中的嵌套布局是不需要的,许多糟糕的设计都会考虑这样做。

进行我上面建议的更改,删除内部 ConstraintLayout 并将两个视图放入垂直链中,如下所示:

<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_
    android:layout_
    android:background="#cccccc">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/conversationRecyclerView"
        android:layout_
        android:layout_
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:paddingBottom="10dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constrainedHeight="true"
        app:layout_constraintBottom_toTopOf="@+id/sendMessageEditText"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/sendMessageEditText"
        android:layout_
        android:layout_
        android:text="This is the EditText"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/conversationRecyclerView" />

</androidx.constraintlayout.widget.ConstraintLayout>

【讨论】:

在最后一个代码中我需要添加 0dp 吗? 需要在父视图中删除匹配父对象? 我添加了更新的代码,但仍然无法正常工作

以上是关于在 Android Kotlin 的约束布局中设置适当的约束的主要内容,如果未能解决你的问题,请参考以下文章

代码中设置的自动布局约束未出现在界面生成器中

Barrier 未在约束布局中设置为 referenceIds?

在自动布局中设置约束,以便 UIView 包装可见的子项

在代码中设置自动布局约束时出现奇怪的问题

我们如何在 uitableview 单元格中设置标签约束?

在代码中设置 IBOutlet 的 Auto Layout 约束