【问题标题】:ConstraintLayout, when constraint dependent view is gone, the layout view behave weirdlyConstraintLayout,当约束依赖视图消失时,布局视图行为怪异
【发布时间】:2017-07-13 12:37:30
【问题描述】:

我正在使用 ConstraintLayout,如下所示

我想隐藏First(使用gone),以及我希望如下所示的视图(ElasticBody 也将延伸到原来的First 视图空间。

但是,当我实际将First 设置为gone 时,我的视图结果如下(所有图像均来自 Android Studio 设计视图)。我的Elastic Body 也不见了,而且高度变大了。

我的布局代码如下

<android.support.constraint.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="wrap_content"
    android:padding="16dp">

    <TextView
        android:id="@+id/txt_first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#0ff"
        android:text="First"
        android:visibility="gone"
        android:textSize="26sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/txt_body"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/txt_body"
        android:layout_width="0dp"
        android:background="#f0f"
        android:layout_height="wrap_content"
        android:text="Elastic Body"
        android:textSize="26sp"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/txt_tail"
        app:layout_constraintStart_toEndOf="@+id/txt_first"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/txt_tail"
        android:background="#ff0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Tail"
        android:textSize="26sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/txt_body"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

(注意,如果您删除gone,您将获得第一个图像视图)。 为什么会这样?当我的First 消失时,我该如何修复它,Elastic Body 可以正确伸展吗?

p/s:我知道如何在 LinearLayout 和 RelativeLayout 中做到这一点...但想知道这是否是对 ConstraintLayout 的限制?

【问题讨论】:

  • 老兄,你的代码有错别字... constraintTop_toBTopOf

标签: android android-layout android-constraintlayout


【解决方案1】:

您可以在ConstraintLayout 中为Visibility.GONE 使用另一件事:Barriers

如果您不知道Barriers,请查看:Barriers

【讨论】:

【解决方案2】:

尝试关注。

将第一个视图的左侧和顶部约束设置为“父级”。之后:

  • 将 txt_body 文本视图宽度设置为“0dp”
  • 将左侧约束设置为第一个视图的右侧
  • 将右约束设置为尾视图的左侧。

因此,每当您将第一个视图的可见性设置为“已消失”时,主体视图就会按照您想要的方式拉伸。

<android.support.constraint.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="wrap_content"
    android:padding="16dp">

    <TextView
        android:id="@+id/txt_first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#0ff"
        android:text="First"
        android:textSize="26sp"
        android:visibility="gone"
        app:layout_constraintEnd_toStartOf="@+id/txt_body"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent" />

    <TextView
        android:id="@+id/txt_body"
        android:layout_width="0dp"
        android:background="#f0f"
        android:layout_height="wrap_content"
        android:text="Elastic Body"
        android:textSize="26sp"
        app:layout_constraintRight_toLeftOf="@+id/txt_tail"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/txt_first"
        />

    <TextView
        android:id="@+id/txt_tail"
        android:background="#ff0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Tail"
        android:textSize="26sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

</android.support.constraint.ConstraintLayout>

更新

如果你想使用屏障,那么你也可以这样做。

<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="wrap_content"
    android:padding="16dp">

    <TextView
        android:id="@+id/txt_first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#0ff"
        android:text="First"
        android:textSize="26sp"
        android:visibility="gone"
        app:layout_constraintEnd_toStartOf="@+id/barrier"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/txt_body"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#f0f"
        android:text="Elastic Body"
        android:textSize="26sp"
        app:layout_constraintStart_toEndOf="@+id/barrier"
        app:layout_constraintEnd_toStartOf="@+id/txt_tail"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/txt_tail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ff0"
        android:text="Tail"
        android:textSize="26sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="start"
        app:constraint_referenced_ids="txt_body,txt_first" />

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="end"
        app:constraint_referenced_ids="txt_body,txt_tail" />

</androidx.constraintlayout.widget.ConstraintLayout>

【讨论】:

  • 谢谢。有趣的是,从 tail 中删除 app:layout_constraintStart_toEndOf="@+id/txt_body" 会有所帮助。点赞你的答案。你能详细说明背后的逻辑吗?谢谢! (不确定谁不投票,他们至少应该给出一个理由......)
  • 想了一会儿,我想我明白其中的逻辑了。我把你的作为答案。谢谢! (如果您认为这对其他人有帮助,请支持我的问题)
  • 否决票可能是因为您说“试试这个”并显示了一堆代码。没有解释你做了什么,你甚至没有突出显示有意义的代码行。但后来我猜,因为我没有投反对票。因此,请添加一些关于您的建议的评论,因为阅读代码很糟糕。
  • 支持它,因为它仍然是一个答案和产生的努力
【解决方案3】:

说,你想要这样的图片:

标题和“好作品”之间、“好作品”和时间之间有缩进,“意见”也有水平缩进。它们垂直居中。

“意见”附在星号上,因此可以多行并保持居中。我展示了 2 个变体的结果:第一行意见是多行的,而下一行是单行。在列中,您可以看到显示/隐藏 2 个标签的 4 种变体。

  1. 一种更简单、更可取的方法是将两个标签包装到LinearLayout 中,然后将其插入父ConstraintLayout。然后你可以设置垂直重力,显示或隐藏标签,隐藏LinearLayout本身。

  2. 如果您不想嵌套布局,请使用Barriers 和Groups。这是一项艰巨的任务,可能会浪费很多时间。一个关键是有额外的Views 用于对齐。这里我有 2 个隐藏标签(“Nice work”和“Opinions”),我必须添加 2 个视图(空格)。

右边空间的高度等于星星的高度(14dp)。

为了简化隐藏多个视图,我将它们组合成组。

您可以看到水平虚线 - 它们是Barriers。我将它们对齐在最大视图的顶部和底部(barrier_2 类似):

<androidx.constraintlayout.widget.Barrier
    android:id="@+id/barrier_1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:barrierDirection="top"
    app:constraint_referenced_ids="left_text,opinion" />

垂直对齐基于这两个额外的Spaces(见marginTop="10dp"):

<Space
    android:id="@+id/left_text_space"
    android:layout_width="25dp"
    android:layout_height="10dp"
    android:layout_marginTop="10dp"
    app:layout_constraintStart_toEndOf="@id/left_text"
    app:layout_constraintTop_toBottomOf="@id/title" />

很难涵盖所有情况,所以请看下面的布局:

<?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"
    android:paddingLeft="15dp"
    android:paddingTop="5dp"
    android:paddingRight="15dp"
    android:paddingBottom="5dp">

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:lineSpacingExtra="4sp"
        android:lines="1"
        android:paddingBottom="5dp"
        android:text="«Title text»"
        android:textColor="#333333"
        android:textSize="15sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="top"
        app:constraint_referenced_ids="left_text,opinion" />

    <TextView
        android:id="@+id/left_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#112233"
        android:paddingLeft="5dp"
        android:paddingTop="4dp"
        android:paddingRight="5dp"
        android:paddingBottom="4dp"
        android:text="Nice work"
        android:textColor="#ffffff"
        android:textSize="13sp"
        app:layout_constraintBottom_toBottomOf="@id/barrier_2"
        app:layout_constraintStart_toStartOf="@id/title"
        app:layout_constraintTop_toTopOf="@id/left_text_space" />

    <Space
        android:id="@+id/left_text_space"
        android:layout_width="25dp"
        android:layout_height="10dp"
        android:layout_marginTop="10dp"
        app:layout_constraintStart_toEndOf="@id/left_text"
        app:layout_constraintTop_toBottomOf="@id/title" />

    <androidx.constraintlayout.widget.Group
        android:id="@+id/left_text_group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="visible"
        app:constraint_referenced_ids="left_text,left_text_space" />

    <Space
        android:id="@+id/opinion_space"
        android:layout_width="1dp"
        android:layout_height="14dp"
        android:layout_marginTop="10dp"
        app:layout_constraintStart_toStartOf="@id/left_text_space"
        app:layout_constraintTop_toBottomOf="@id/title" />

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="left_text,opinion" />

    <ImageView
        android:id="@+id/opinion_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:contentDescription="@null"
        app:layout_constraintBottom_toBottomOf="@id/barrier_2"
        app:layout_constraintStart_toEndOf="@id/left_text_space"
        app:layout_constraintTop_toTopOf="@id/opinion_space"
        app:srcCompat="@drawable/ic_filled_rate_star" />

    <TextView
        android:id="@+id/opinion"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="5dp"
        android:layout_marginLeft="5dp"
        android:lineSpacingExtra="1sp"
        android:text="1. Opinion 1.\n2. Opinion 2.\n3. Opinion 3.\n4. Opinion 4."
        android:textColor="#1122aa"
        android:textSize="12sp"
        app:layout_constraintBottom_toBottomOf="@id/opinion_icon"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@id/opinion_icon"
        app:layout_constraintTop_toTopOf="@id/opinion_icon" />

    <androidx.constraintlayout.widget.Group
        android:id="@+id/opinion_group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="visible"
        app:constraint_referenced_ids="opinion_icon,opinion,opinion_space" />

    <ImageView
        android:id="@+id/time_icon"
        android:layout_width="15dp"
        android:layout_height="15dp"
        android:layout_gravity="center_vertical"
        android:layout_marginTop="8dp"
        android:contentDescription="@null"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/barrier_2"
        app:srcCompat="@drawable/ic_time" />

    <TextView
        android:id="@+id/time"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="7dp"
        android:layout_marginLeft="7dp"
        android:ellipsize="end"
        android:lineSpacingExtra="1sp"
        android:lines="2"
        android:paddingBottom="7dp"
        android:text="17:00"
        android:textColor="#9e9e9e"
        android:textSize="11sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@id/time_icon"
        app:layout_constraintTop_toTopOf="@id/time_icon" />

</androidx.constraintlayout.widget.ConstraintLayout>

然后在您的活动中,您可以显示/隐藏标签。隐藏Groups,而不是里面的视图,因为奇怪的是,Group 里面的视图总是可见的。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_activity)

    left_text_group.visibility = View.GONE
    opinion_group.visibility = View.VISIBLE
}

【讨论】:

  • 这么好的解释。并适合我们的用例
  • 有什么办法可以在障碍物的另一边使用图像,当文本行增加时降低图像的高度
  • @ArulMani,对不起,我不知道。也许截图会有所帮助,但我几乎不会创建项目。
【解决方案4】:

已经给出了链接到Barriers 的答案。我将提供一个示例来说明我是如何实际实现它的:

<TextView
    android:id="@+id/textView1"
    app:layout_constraintTop_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    android:text="Some text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/textView2"
    app:layout_constraintTop_toBottomOf="@id/textView1"
    app:layout_constraintLeft_toLeftOf="parent"
    android:text="Some other text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
<androidx.constraintlayout.widget.Barrier
    android:id="@+id/barrier1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:barrierDirection="bottom"
    app:constraint_referenced_ids="textView1,textView2" />

此示例显示 2 个TextViews,其中任何一个都可以是gone。视图从上到下堆叠,因此barrierDirection 设置为bottom。如果您需要其他方向,只需相应地更改该行即可。

将两个TextViews 中的任何一个设置为gone,将导致Barrier 移动到另一个的底部,如果我们将两者都设置为gone,它只会向上移动到元素textView1 的最高约束是引用,在这种情况下,是父级。

注意:如果您的 textView1 的顶部约束是别的东西,即它在另一个元素下方,如果两个视图都设置为 gone,那么障碍将在那里结束。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 2023-04-07
    • 1970-01-01
    • 2017-10-09
    • 2021-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多