【问题标题】:Cannot align rows with chain restraints无法将行与链约束对齐
【发布时间】:2022-11-19 01:09:54
【问题描述】:

我有一个小部件,无论我对它和其他小部件施加什么限制,包括添加障碍,它始终将自己定位在布局的顶部。

这是一个相当简单的排列,两行,每行两个元素,不是按列对齐。每行中的第一个元素是 TextView 标签,第二个元素是输入 (Spinner)。 第一行上方还有一个单独的 TextView 标题,一直延伸到整个行。根据我对约束布局的理解和以前的经验,这不应该要求行之间有障碍,这是我的初始版本。

这是设计视图,其中所选元素(“Credentials”)应该位于第二行,但实际上出现了以上第一行,在标题 TextView(“PKIX”)之上:

模拟器中的实际结果看起来大同小异。所选的“Credentials”元素是下面 XML 布局中五个元素中的第四个。所有其他元素都在正确的位置。

<?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">

    <TextView
        android:id="@+id/addsrv_pkix_title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@drawable/bottomborder"
        android:text="PKIX"
        android:textAlignment="center"
        android:layout_marginHorizontal="10sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/addsrv_trust_lbl"
        />

    <TextView
        android:id="@+id/addsrv_trust_lbl"
        android:text="Trust"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingHorizontal="10sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/addsrv_trust_spin"
        app:layout_constraintTop_toBottomOf="@+id/addsrv_pkix_title"
        app:layout_constraintBaseline_toBaselineOf="@+id/addsrv_trust_spin"
        app:layout_constraintBottom_toTopOf="@+id/addsrv_cred_lbl"
        />

    <Spinner
        android:id="@+id/addsrv_trust_spin"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toEndOf="@+id/addsrv_trust_lbl"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/addsrv_pkix_title"
        app:layout_constraintBottom_toTopOf="@+id/addsrv_cred_spin"
        />

    <TextView
        android:id="@+id/addsrv_cred_lbl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:paddingHorizontal="10sp"
        android:text="Credentials"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/addsrv_cred_spin"
        app:layout_constraintTop_toBottomOf="@+id/addsrv_trust_lbl"
        app:layout_constraintBaseline_toBaselineOf="@+id/addsrv_cred_spin"
        />

    <Spinner
        android:id="@+id/addsrv_cred_spin"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toEndOf="@+id/addsrv_cred_lbl"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/addsrv_trust_spin"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

我很困惑。 addsrv_cred_lbl TextView(“凭证”)是:

  • 开始与父对齐。
  • 结束与 addsrv_cred_spin 微调器对齐,显示位置正确; 这种对齐往复运动以创建水平链。他们也是基线 对齐。
  • 顶部与其上方的 TextView 的底部对齐,addsrv_trust_lbl。 这种排列也是往复的。

还没有底部对齐(还有另一行要走);将它与父级底部对齐没有区别,除非我从同一行底部对齐微调器,在这种情况下,结果会变得越来越糟。

由于这不起作用,我尝试在行之间使用屏障。如果我将它用作“顶部”,将第二行小部件用作约束参照物,则屏障出现在标题上方的顶部,无论使用什么约束将其定位在第一行下方。用作“底部”,引用第一行小部件,第二行链接在它下面(这更符合逻辑),事情要好一些,因为屏障出现在正确的位置——但是“凭证”小部件仍然在顶部。

这个设计视图看起来与之前的设计视图完全相同,只是屏障在第一行下方可见。在 XML 中,我在阅读后添加了 optimizationLevel="none" 可以帮助解决行为不当的障碍(但没有任何区别)。这里还添加了一些样式元素(例如字体大小),我之前为简洁起见删除了这些元素。

<?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"
    app:layout_optimizationLevel="none"
    >

    <TextView
        android:id="@+id/addsrv_pkix_title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@drawable/bottomborder"
        android:backgroundTint="@color/tbar"
        android:text="PKIX"
        android:textAlignment="center"
        android:textSize="@dimen/addsrv_bigfont"
        android:textColor="@color/titleText"
        android:layout_marginHorizontal="10sp"
        app:layout_constraintBottom_toTopOf="@+id/addsrv_trust_lbl"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />

    <TextView
        android:id="@+id/addsrv_trust_lbl"
        android:text="Trust"
        android:textSize="@dimen/addsrv_fontsz"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingHorizontal="10sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/addsrv_trust_spin"
        app:layout_constraintTop_toBottomOf="@+id/addsrv_pkix_title"
        app:layout_constraintBaseline_toBaselineOf="@+id/addsrv_trust_spin"
        app:layout_constraintBottom_toTopOf="@+id/addsrv_bar1"
        app:layout_constraintHorizontal_chainStyle="packed"
        />

    <Spinner
        android:id="@+id/addsrv_trust_spin"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toEndOf="@+id/addsrv_trust_lbl"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/addsrv_pkix_title"
        app:layout_constraintBottom_toTopOf="@+id/addsrv_bar1"
        />

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/addsrv_bar1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="addsrv_trust_lbl,addsrv_trust_spin"
        app:layout_constraintBottom_toTopOf="@+id/addsrv_cred_lbl"
        />

    <TextView
        android:id="@+id/addsrv_cred_lbl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"        
        android:paddingHorizontal="10sp"
        android:text="Credentials"
        android:textSize="@dimen/addsrv_fontsz"
        app:layout_constraintBaseline_toBaselineOf="@+id/addsrv_cred_spin"
        app:layout_constraintEnd_toStartOf="@+id/addsrv_cred_spin"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/addsrv_bar1" />

    <Spinner
        android:id="@+id/addsrv_cred_spin"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toEndOf="@+id/addsrv_cred_lbl"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/addsrv_bar1"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

我是否正确地观察到 addsrv_cred_lbl 上的一些约束被完全忽略了?topToBottom 是否意味着小部件的顶部与另一个小部件的底部对齐?相反,它似乎只是意味着它们将在设计视图中与一条波浪形的、可能弯曲的和盘旋的线连接,并且两个小部件的空间关系是任意的,这样语义逻辑还不如颠倒过来,“top = 底部,底部 = 顶部”,等等。

请注意我不想使用绝对值来定位任何东西.如果让它工作的唯一方法就是那样做,那么即使在这种简单的情况下,约束布局似乎也完全是在浪费时间,我宁愿只是堆叠一些线性布局。

【问题讨论】:

  • 我已经删除了基线约束,它看起来不错。您确定 Spinner 有 baseline 吗?
  • 问题似乎是您试图将第二行的 lavbel 与 Spinner 的基线联系起来。我不确定 Spinner 是否有类似的东西。我尝试了第一个例子,只是把它绑在底部而不是基线,它似乎定位正确。
  • 是的,这行得通(我还必须删除一个 24sp 的顶部边距,它在某个时候被设计视图偷偷放入“凭据”小部件,在这里也删除了它)。不知道为什么我会被允许创建一个基线约束,如果它实际上没有用的话(为什么显示文本的微调器没有基线?)。另外,即使这样也很棒一堆边缘虚假警告(“硬编码文本”,“颜色对比度不足”......)提到了这一点。现在也不需要屏障了。呃呃。安薇:谢谢。

标签: android android-constraintlayout


【解决方案1】:

问题是Spinner 没有基线。你试图将它绑定到 Spinner 中的项目的基线是我的猜测 - ConstraintLayout 无法到达其孩子的孩子。

您可以通过右键单击设计选项卡进行检查。 TextViews 将显示一个选项“显示基线”,但 Spinner 不会。

还有文档中的 sn-p

将视图的文本基线与另一个视图的文本基线对齐 看法。

这就是基线的用途,如果您希望两个 TextViews 连接在一起,这样它们就不会在文本开始时出现混乱的高度。

我认为您的链条方法存在一个小缺陷。您将每行中两个元素的顶部约束设置为前一行(或第一行中的标题)的底部。即使 Spinner 有基线,这也会使标签相对于 Spinner 偏心(略高,因为文本的基线高于视图的实际底部)。

我认为在这些类型的布局中,最好的方法是使用一个引导元素(也是链中的元素)来表示该行,并让其他元素相对于它定位。

<?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">

    <TextView
        android:id="@+id/addsrv_pkix_title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="PKIX"
        android:textAlignment="center"
        android:layout_marginHorizontal="10sp"
        app:layout_constraintVertical_chainStyle="spread"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/addsrv_trust_spin"
        />

    <TextView
        android:id="@+id/addsrv_trust_lbl"
        android:text="Trust"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingHorizontal="10sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/addsrv_trust_spin"
        app:layout_constraintTop_toTopOf="@+id/addsrv_trust_spin"
        app:layout_constraintBottom_toBottomOf="@+id/addsrv_trust_spin"
        />

    <Spinner
        android:id="@+id/addsrv_trust_spin"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toEndOf="@+id/addsrv_trust_lbl"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/addsrv_pkix_title"
        app:layout_constraintBottom_toTopOf="@+id/addsrv_cred_spin"
        />

    <TextView
        android:id="@+id/addsrv_cred_lbl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingHorizontal="10sp"
        android:text="Credentials"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/addsrv_cred_spin"
        app:layout_constraintTop_toTopOf="@+id/addsrv_cred_spin"
        app:layout_constraintBottom_toBottomOf="@+id/addsrv_cred_spin"
        />

    <Spinner
        android:id="@+id/addsrv_cred_spin"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toEndOf="@+id/addsrv_cred_lbl"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/addsrv_trust_spin"
        app:layout_constraintBottom_toBottomOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

注意:我将最后一个底部约束添加到父级,并将“spread”添加到链中以进行演示,但我也知道,如果您没有将最后一个视图的底部约束到某些东西 - 它不是链。

【讨论】:

    【解决方案2】:

    如果您遵守一些简单的规则,使用ConstraintLayout 会很容易:

    1. 创建一个链。这意味着 Views 一直相互挂钩。
    2. 现在你有了一个工作链,你可以用layout_constraintVertical_biaslayout_constraintVertical_chainStyle来操作它。如果更改这些没有任何作用,则意味着您的链条已损坏。
    3. 将剩余的 Views 挂钩到链条布局的 Views
    4. 每个控件必须有 4 个约束:top、bottom、start 和 end
    5. 不要创建竞争链并试图强迫它们一起工作。

      Spinner 不能有基线,只有 TextView 和它的后代有。 SpinnerAdapterView,所以它可以包含你能想到的任何东西。

      顺便说一句:不要使用@+id 来引用现有的ID。 Plus 意味着创建新的 ID,因此如果您输入错误,它将创建一个没有引用任何内容的新 ID,而不是错误“没有这样的 ID”。

      这是一个示例:顶部标签和微调器形成主链,侧标签分别定位到它们的微调器:

          <?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"
          >
      
          <TextView
              android:id="@+id/addsrv_pkix_title"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_marginHorizontal="10sp"
              android:background=""
              android:text="PKIX"
              android:textAlignment="center"
              app:layout_constraintBottom_toTopOf="@id/addsrv_trust_spin"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toTopOf="parent"
              app:layout_constraintVertical_bias="0.0"
              app:layout_constraintVertical_chainStyle="packed"
              />
      
          <TextView
              android:id="@+id/addsrv_trust_lbl"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:paddingHorizontal="10sp"
              android:text="Trust"
              app:layout_constraintBottom_toBottomOf="@id/addsrv_trust_spin"
              app:layout_constraintEnd_toStartOf="@id/addsrv_trust_spin"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toTopOf="@id/addsrv_trust_spin"
              app:layout_constraintVertical_bias="1.0"
              />
      
          <Spinner
              android:id="@+id/addsrv_trust_spin"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              app:layout_constraintBottom_toTopOf="@id/addsrv_cred_spin"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintStart_toEndOf="@id/addsrv_trust_lbl"
              app:layout_constraintTop_toBottomOf="@id/addsrv_pkix_title"
              app:layout_constraintVertical_bias="0.0"
              />
      
          <TextView
              android:id="@+id/addsrv_cred_lbl"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:paddingHorizontal="10sp"
              android:text="Credentials"
              app:layout_constraintBottom_toBottomOf="@id/addsrv_cred_spin"
              app:layout_constraintEnd_toStartOf="@id/addsrv_cred_spin"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toTopOf="@id/addsrv_cred_spin"
              app:layout_constraintVertical_bias="1.0"
              />
      
          <Spinner
              android:id="@+id/addsrv_cred_spin"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              app:layout_constraintBottom_toBottomOf="parent"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintStart_toEndOf="@id/addsrv_cred_lbl"
              app:layout_constraintTop_toBottomOf="@id/addsrv_trust_spin"
              />
      </androidx.constraintlayout.widget.ConstraintLayout>
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多