【问题标题】:How to center multiple Views together using ConstraintLayout?如何使用 ConstraintLayout 将多个视图集中在一起?
【发布时间】:2016-09-27 04:26:39
【问题描述】:

背景

Google 宣布了一种名为“ConstraintLayout”的新布局,它应该是终极布局,它可以取代所有布局,同时保持平坦(没有嵌套布局)并具有更好的性能。

问题

问题是,除了 Google IO 上的视频之外,我几乎看不到任何可以帮助我解决这个问题的教程。

我想做的是,鉴于我在另一个布局中有一个垂直居中的 LinearLayout - 将它们都转换为一个 ConstraintLayout。

毕竟这就是这个新布局的目的……

我希望处理的布局如下所示:

注意中间的views只是垂直居中,两个textView在ImageView的右边,也是垂直居中的。

这一切都适用于RelativeLayout,它具有2个TextView的LinearLayout,但我想知道如何将它们转换为单个ConstraintLayout。

这是我展示的示例 XML:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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"
    android:minHeight="?attr/listPreferredItemHeightSmall">

    <ImageView
        android:id="@+id/appIconImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:layout_marginEnd="4dp"
        android:layout_marginLeft="2dp"
        android:layout_marginRight="4dp"
        android:layout_marginStart="2dp"
        android:adjustViewBounds="true"
        android:src="@android:drawable/sym_def_app_icon"
        tools:ignore="ContentDescription"/>

    <LinearLayout
        android:id="@+id/appDetailsContainer"
        android:layout_width="0px"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toEndOf="@+id/appIconImageView"
        android:layout_toLeftOf="@+id/overflowView"
        android:layout_toRightOf="@+id/appIconImageView"
        android:layout_toStartOf="@+id/overflowView"
        android:orientation="vertical">

        <TextView
            android:id="@+id/appLabelTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:text="label"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textDirection="locale"
            tools:ignore="HardcodedText,UnusedAttribute"/>

        <TextView
            android:id="@+id/appDescriptionTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:minLines="3"
            android:text="description"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textDirection="locale"
            tools:ignore="HardcodedText,UnusedAttribute"/>
    </LinearLayout>

    <ImageView
        android:id="@+id/overflowView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:adjustViewBounds="true"
        android:background="?attr/selectableItemBackground"
        android:clickable="true"
        android:padding="10dp"
        app:srcCompat="@drawable/ic_more_vert_black_24dp"

        tools:src="@drawable/ic_more_vert_black_24dp"
        tools:ignore="ContentDescription"/>

    <ImageView
        android:id="@+id/isSystemAppImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignEnd="@+id/overflowView"
        android:layout_alignLeft="@+id/overflowView"
        android:layout_alignParentBottom="true"
        android:layout_alignRight="@+id/overflowView"
        android:layout_alignStart="@+id/overflowView"
        android:adjustViewBounds="true"
        android:scaleType="centerInside"
        app:srcCompat="@drawable/ic_warning_black_24dp"
        tools:ignore="ContentDescription"
        tools:src="@drawable/ic_warning_black_24dp"/>

</RelativeLayout>

我尝试了什么

我尝试阅读一些文章并观看 Google 的一些视频:

那没有帮助,所以我尝试使用它,希望我能自己找出如何使用它。 但我不知道该怎么做。我尝试使用该功能来转换布局,但这会使视图变得一团糟,并添加了我不想拥有的额外边距。

问题

如何将 2 个布局转换为单个 ConstraintLayout ?

【问题讨论】:

  • @pskink Kinda,但居中的视图有 2 个 TextView,一个在另一个下方。不是一个。目前,它们位于居中的 LinearLayout 内。此外,LinearLayout 位于左右视图之间。
  • 您是否尝试过在设计窗格中进行自动转换? “将 转换为 ConstraintLayout”?
  • @DevrimTuncer 是的。结果根本没有变平。你可以在这里看到我的尝试:code.google.com/p/android/issues/detail?id=212116

标签: android android-layout android-constraintlayout


【解决方案1】:

看看我的回答here

ContraintLayout 包含一个功能 - Chains - 可以实现您的要求:

链在单轴(水平或 垂直)。

如果一组小部件通过以下方式链接在一起,则它们被视为一个链 双向连接

一旦创建了一个链,就有两种可能:

  • 在可用空间中散布元素
  • 链也可以“打包”,在这种情况下,元素被组合在一起

至于你的情况,你必须打包你的 labeldescription TextViews 并将它们垂直居中在你的父级中:

(确保您使用支持链的ConstraintLayout 版本)

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:text="TextView"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintLeft_toRightOf="@+id/imageView2"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintHorizontal_chainStyle="packed"/>

    <TextView
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="Button\nMkay"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/imageView2"
        app:layout_constraintTop_toBottomOf="@+id/textView"/>

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:layout_marginTop="16dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/ic_launcher"/>

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/ic_launcher"/>

    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:layout_marginEnd="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:srcCompat="@mipmap/ic_launcher"/>
</android.support.constraint.ConstraintLayout>

2019 年 6 月 25 日更新 (@Saeid Z):

现在在约束布局 1.1.3 中,我们必须使用 app:layout_constraintHorizontal_chainStyle="packed" 而不是 app:layout_constraintVertical_chainPacked="true"

【讨论】:

  • 它如何将视图组合在一起?
  • 它使用了 ConstraintLayout 的一个新特性——链。查看我的其他答案,了解更多信息和链接
  • 链的定义是“如果一组小部件通过双向连接链接在一起,则它们被视为链” - 示例中的两个视图相互依赖(textView 是在按钮上方,而按钮在 textView 下方),因此它们被称为链并组合在一起。请点击链接并找到更多信息。
  • 我不知道实现细节。我所知道的是,在约束中相互引用的视图构成了一个链,其行为由其第一个成员定义。
  • @Yury Fedorov 谢谢。现在在约束布局 1.1.3 中,我们必须使用 app:layout_constraintHorizo​​ntal_chainStyle="packed" 而不是 app:layout_constraintVertical_chainPacked="true"
【解决方案2】:

app:layout_constraintVertical_bias="0.5" 设置为需要垂直居中的视图,bias 属性仅在您指定边界约束时才有效(例如,top 和 bottom 用于垂直偏移,left 和 right 用于水平偏移)

一个例子:

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/constraintLayout">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="@id/constraintLayout"
        app:layout_constraintBottom_toBottomOf="@id/constraintLayout"
        app:layout_constraintVertical_bias="0.5" />

</android.support.constraint.ConstraintLayout>

让它在我的布局中工作:https://github.com/hidroh/tldroid/blob/master/app/src/main/res/layout/activity_main.xml,布局非常相似,尽管我将东西放置在屏幕高度的 1/3 处。

【讨论】:

  • 我不明白。我有 2 个文本视图。我可能有更多。我希望它们垂直居中。我该怎么办?
  • 我的布局有 2 个 TextView。我只举例说明如何在 ConstraintLayout 中垂直居中 1 个视图。如果您想要一堆,请为它们中的每一个设置偏差属性。就我而言,我只设置了 1 个 TextView,并将其用作另一个的锚点。
  • 您能说明如何处理我提出的案例吗?一个 TextView 在另一个之上,而两者一起居中?
  • 你看过我回答中的 Github 文件了吗?几乎相同,只需将布局中的偏差值更改为 0.5 而不是 0.3。
【解决方案3】:

编辑:此答案是在链可用之前编写的。请立即使用链,请参阅上面的答案:https://stackoverflow.com/a/40102296/1402641


目前我相信您唯一的选择是将两个文本视图包装在另一个布局中 - 可能线性布局最适合这种情况。

但是约束布局背后的团队说他们想要引入“虚拟容器”,它正好服务于这个用例:你将两个或多个视图组合在一起,并在容器上设置一个约束(比如垂直居中)。这个想法是它不是约束布局内的完整嵌套布局,而只是约束布局用来定位其子级的东西 - 因此它应该提供比嵌套更好的性能。

他们在their I/O talk 中提到了它(链接到确切的时间)。所以我想请继续关注。

【讨论】:

  • 但是RelativeLayout里面已经有了LinearLayout。将其全部展平以具有单一布局不是重点吗?我的场景有那么特别吗?
  • 是的,关键是要扁平化。您的情况并不特殊,只是尚未处理。它只是在版本alpha2 上。虚拟小组来处理您的场景。
  • 如何使用“虚拟群组”?有这方面的例子吗?我想我没看到。
  • 虚拟组还不存在。这是ConstraintLayout 背后的团队想要引入的概念。他们决定提前发布,没有所有功能,也没有处理所有常见情况。
  • 实际上我设法在 I/O 谈话中找到了 :) 但他们称之为“虚拟容器”,所以我将编辑我的答案并发布链接。
【解决方案4】:

要垂直或水平居中,请在布局上设置opposing constraint

垂直居中

    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"

水平居中

    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"

【讨论】:

  • 请先看这个how-to-answer这个问题之前回答过,显然,你可以在这里添加你的答案。但是在回答之前,您需要了解一些要点。首先,不要添加以前使用相同代码或建议添加的答案。其次,如果用户已经非常具体地询问了问题以及他需要解决什么问题,请不要添加过于复杂的答案。第三,如果您想对答案或问题提出任何建议,可以添加评论。
  • 这个唯一的中心单视图
【解决方案5】:

看看我的例子 (Center components in ConstraintLayout)

现在您可以将“图像”居中(约束左上-下),将“标签”顶部约束到“图像”顶部,将“描述”顶部约束到“标签”底部。 在下面的示例中,我将按钮高度与右侧的两个文本视图匹配(这是您的情况)。其他文本视图受到上述链接的限制。

更新:在下面回答您的评论:

我已经安装了你的应用程序,这只是我目前能想到的。由于它是一个 ViewHolder 布局,因此 layout_height 可以设置为 wrap_content,或者您可以根据需要对其进行修复。如果你愿意,我可以给你发送 xml,我不想淹没答案。

Top TextView 的左约束被约束为 ImageView 的右约束。此外,顶部 TextView -> 顶部约束被限制在容器顶部,所以是正确的。底部 TextView 被限制在容器底部。中间的 TextView 被限制为匹配顶部 TextView 的宽度,并且与 ImageView 没有任何连接。

【讨论】:

  • 我询问了将 2 个视图(一起)居中的问题。没有。
  • @androiddeveloper 是的,我知道,我提供了一种解决方法。它在视觉上看起来是一样的。当然,问题仍然存在,因为我们都希望将多个相互约束的组件居中。
  • 实际上,就我而言,这可能是一个不错的解决方法。我使用的布局用于 RecyclerView 中的项目(在这个应用程序中:play.google.com/store/apps/details?id=com.lb.app_manager)。也许我可以将顶部 TextView 设置为顶部(但有重力底部),并将底部 TextView 设置为底部(顶部 TextView 下方)。你认为它可以看起来一样吗?
  • @androiddeveloper 我已经用您的应用程序中特定的布局更新了我的答案。希望对您有所帮助。
  • 有时间我会试试的。正如我所注意到的,直到最近他们才修复了一个错误,该错误会阻止新布局在 RecyclerView 中使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-25
  • 1970-01-01
  • 1970-01-01
  • 2021-12-10
  • 2021-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多