如何在ConstraintLayout中使视图“wrap_content但不超过”?

43

我有三个视图,分别是标题、版本和ImageView(作为按钮):

  1. 标题应该是wrap_content,但要遵守以下规则
  2. 版本应该是wrap_content,在标题右侧且在ImageView左侧
  3. ImageView具有固定大小,位于父视图的右上角

enter image description here

问题在于,如果标题太大,版本号将向右移动,并且“版本号在ImageView左侧”规则将不被遵守:

enter image description here

因此,我需要限制标题宽度,使版本号可见且不向右移动。

这是XML:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:background="#b3b2b2">

    <!--  -->
    <TextView
        android:id="@+id/LibraryWithVersionItem.title"
        android:layout_width="0dp"
        android:textStyle="bold"
        android:textSize="@dimen/fontSize18"
        android:textColor="@color/mySecondaryDarkColor"
        android:layout_height="wrap_content"
        android:ellipsize="middle"
        tools:text="ExampleLibrary 01234567890123456789012345"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        />

    <Spinner
        android:id="@+id/LibraryWithVersionItem.versions"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:textSize="@dimen/fontSize16"
        android:textColor="@color/mySecondaryDarkColor"
        tools:listitem="@layout/library_version"
        android:layout_marginTop="@dimen/margin8"
        android:layout_marginLeft="@dimen/margin8"
        android:layout_marginRight="@dimen/margin8"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/LibraryWithVersionItem.title"
        app:layout_constraintRight_toLeftOf="@+id/LibraryWithVersionItem.info"
        app:layout_constraintHorizontal_bias="0.0"/>

    <TextView
        android:id="@+id/LibraryWithVersionItem.sentence"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/LibraryWithVersionItem.title"
        tools:text="Some library description in one sentence\nbut two lines"
        android:layout_marginTop="@dimen/margin8"
        android:layout_marginLeft="@dimen/margin8"
        app:layout_constraintRight_toLeftOf="@+id/LibraryWithVersionItem.install"
        android:layout_marginRight="8dp"
        app:layout_constraintHorizontal_bias="0.0"/>

    <TextView
        android:id="@+id/LibraryWithVersionItem.isInstalled"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/LibraryManager.installed"
        android:textColor="#1a7c1a"
        android:layout_marginTop="@dimen/margin8"
        android:layout_marginBottom="@dimen/margin8"
        android:layout_marginLeft="@dimen/margin8"
        android:layout_marginRight="@dimen/margin8"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/LibraryWithVersionItem.sentence"
        app:layout_constraintRight_toLeftOf="@+id/LibraryWithVersionItem.install"
        app:layout_constraintHorizontal_bias="0.0"/>

    <!-- information button -->
    <ImageView
        android:id="@+id/LibraryWithVersionItem.info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/margin8"
        android:paddingLeft="@dimen/margin8"
        android:paddingRight="@dimen/margin8"
        android:paddingBottom="@dimen/margin8"
        android:scaleType="center"
        android:src="@drawable/ic_info_outline_white_24dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <!-- install button -->
    <ImageView
        android:id="@+id/LibraryWithVersionItem.install"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="@dimen/margin8"
        android:paddingRight="@dimen/margin8"
        android:paddingTop="@dimen/margin8"
        android:paddingBottom="@dimen/margin8"
        android:scaleType="center"
        android:src="@drawable/ic_get_app_white_24dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/LibraryWithVersionItem.info"/>


</android.support.constraint.ConstraintLayout>

PS 1. layout_width="0dp" + app:layout_constraintWidth_default="wrap" 看起来正是我所需要的("wrap_content但不破坏约束"), 但它并不起作用(仍然比所需的大):

<TextView
        android:id="@+id/LibraryWithVersionItem.title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:ellipsize="middle"
        android:textColor="@color/mySecondaryDarkColor"
        android:textSize="@dimen/fontSize18"
        android:textStyle="bold"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="wrap"
        tools:text="ExampleLibrary 01234567890123456789012345"

PS 2. 设置版本的最小约束宽度(app:layout_constraintWidth_min="60dp")也没有帮助 - 它是不可见的,因为它被移动得太靠右了。

4个回答

50

标题和版本应该添加到链中,并使用app:layout_constraintWidth_default =“wrap”

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:background="#b3b2b2">

    <!-- information button -->
    <ImageView
        android:id="@+id/LibraryWithVersionItem.info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/margin8"
        android:paddingLeft="@dimen/margin8"
        android:paddingRight="@dimen/margin8"
        android:paddingBottom="@dimen/margin8"
        android:scaleType="center"
        android:src="@drawable/ic_info_outline_white_24dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <!--  -->
    <TextView
        android:id="@+id/LibraryWithVersionItem.title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:ellipsize="middle"
        android:textColor="@color/mySecondaryDarkColor"
        android:textSize="@dimen/fontSize18"
        android:textStyle="bold"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="wrap"
        tools:text="ExampleLibrary 01234567890123456789012345"
        app:layout_constraintRight_toLeftOf="@+id/LibraryWithVersionItem.versions"
        android:layout_marginRight="8dp"
        android:layout_marginLeft="8dp"
        android:paddingBottom="1dp"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="0.0"/>

    <Spinner
        android:id="@+id/LibraryWithVersionItem.versions"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="@dimen/fontSize16"
        android:textColor="@color/mySecondaryDarkColor"
        tools:listitem="@layout/library_version"
        app:layout_constraintRight_toLeftOf="@id/LibraryWithVersionItem.info"
        app:layout_constraintLeft_toRightOf="@+id/LibraryWithVersionItem.title"
        android:layout_marginRight="0dp"
        app:layout_constraintBottom_toBottomOf="@+id/LibraryWithVersionItem.title"
        android:layout_marginBottom="0dp"/>

    <TextView
        android:id="@+id/LibraryWithVersionItem.sentence"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/LibraryWithVersionItem.title"
        tools:text="Some library description in one sentence\nbut two lines"
        android:layout_marginTop="5dp"
        android:layout_marginLeft="@dimen/margin8"
        app:layout_constraintRight_toLeftOf="@+id/LibraryWithVersionItem.install"
        android:layout_marginRight="8dp"
        app:layout_constraintHorizontal_bias="0.0"
        android:layout_marginStart="@dimen/margin8"
        android:layout_marginEnd="8dp"/>

    <TextView
        android:id="@+id/LibraryWithVersionItem.isInstalled"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/LibraryManager.installed"
        android:textColor="#1a7c1a"
        android:layout_marginTop="@dimen/margin8"
        android:layout_marginLeft="@dimen/margin8"
        android:layout_marginRight="@dimen/margin8"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/LibraryWithVersionItem.sentence"
        app:layout_constraintRight_toLeftOf="@+id/LibraryWithVersionItem.install"
        app:layout_constraintHorizontal_bias="0.0"
        android:layout_marginStart="@dimen/margin8"
        android:layout_marginEnd="@dimen/margin8"/>

    <!-- install button -->
    <ImageView
        android:id="@+id/LibraryWithVersionItem.install"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="@dimen/margin8"
        android:paddingRight="@dimen/margin8"
        android:paddingTop="@dimen/margin8"
        android:paddingBottom="@dimen/margin8"
        android:scaleType="center"
        android:src="@drawable/ic_get_app_white_24dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/LibraryWithVersionItem.info"/>

</android.support.constraint.ConstraintLayout>

我试图将版本号与标题基线对齐,但是如果标题有两行或更多行,则它会与第一行对齐,这不是期望的。因此,我必须将版本号与标题底部对齐,并硬编码标题的底部内边距为-3

enter image description here

enter image description here

然而,在 Android Studio 中看起来像期望的那样:

enter image description here

但在硬件设备上看起来不同:enter image description here

当在 Layout Inspector 中进行分析时,我可以看到标题宽度计算错误:enter image description here

可能这是在RecyclerView中使用的副作用,但无论如何...


4
我也注意到了RecyclerView的这个副作用,通过在拉伸的TextView上执行.requestLayout()来解决它,但不确定在onBind中这样做是否高效。 - James Andrew
我在使用ConstraintLayout v1.1.3和RecyclerView时遇到了相同的问题。 - reavcn
我从来不知道app:layout_constraintWidth_default是一个属性,谢谢! - Oblivionkey3
很棒的答案!感谢您的指导。作为2022年的参考,我添加了这个设置,其中包括app:layout_constraintWidth_default="wrap"android:layout_width="0dp", 但是出现了控制台警告。 将其更改为android:layout_width="wrap_content"并添加app:layout_constrainedWidth="true"而不使用app:layout_constraintWidth_default,它可以正常工作,没有控制台错误。 - Pieter van der Vyver

10

你想设置android:layout_width="0dp"

使用wrap_content将使视图随内容无限增长,而使用0dp并设置其约束条件,视图将具有默认的最大大小,并且内容将在达到限制时增长。


使用android:layout_width="wrap_content" 使用android:layout_width="0dp"


使用android:layout_width="0dp" 使用android:layout_width="wrap_content"


从此处开始,进行必要的操作,可以设置TextView的android:maxLines="1"android:ellipsize="end",以在达到最大大小时添加三个点。

MaxLines="1" and Ellipsize="end"

最终的布局xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/item_a_receber_historico"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:maxLines="1"
        android:ellipsize="end"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="John Dreadpool Lennon Of House Stark Man This Name Is Huge!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/item_a_receber_valor"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/item_a_receber_valor"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginTop="8dp"
        android:text="R$420,00"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

我从一开始就使用了<TextView android:id="@+id/LibraryWithVersionItem.title" android:layout_width="0dp",但在RecyclerView中并没有帮助到我。你能检查一下它在你的RecyclerView中是否正常工作吗? - 4ntoine

0
我通过将layout_width设置为wrap_content并将maxWidth设置为某个值来实现这一点。

-2
在ConstraintLayout中,您可以水平或垂直添加一个或多个指南,以帮助将屏幕分成几个部分。我通常使用*_pct属性添加指南,该属性将位置设置为屏幕宽度/高度的百分比。

是的,我知道,但它不起作用,因为它既不是百分比大小也不是固定大小。它是图像wrap_content宽度。 - 4ntoine
设置版本的最小宽度或者最大宽度可以解决你的问题吗? - Juan
版本的最小宽度未知。它可以很容易地是“1.0”和“9.9.9 alpha 34”。 - 4ntoine
我在这里看不到任何问题。标题宽度应根据内容大小和约束条件进行正确计算 - 请参见我的答案。 - 4ntoine
@4ntoine 嗯,我认为你看到了它,只是假设将标题扩展到2行或更多行是可以的。对我来说,这也是一个有效的替代方案。 - Juan
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接