在 Android Studio 中使用约束布局时的奇怪结果

Strange consequence when use Constraint Layout in Android Studio

我正处于 Android 开发的初期阶段。最近,为了练习布局设计,我正在尝试构建一个简单计算器的模拟。我在“设计”选项卡中创建并放置了视图(按钮、EditTexts)。然后我陷入 "This view is not constrained" 错误,所以我在 Whosebug 上搜索,最后找到解决方案是右键单击小部件 -> Constraint Layout -> Infer Constraints。但是当我这样做的时候,我程序中的那些视图发生了严重的变化,我无法将它们修改到原来的位置和大小。如何在不更改视图位置和大小的情况下解决错误?

这是我使用约束布局之前的计算器:

before_constraint:

这是我使用后的计算器:

after_constraint:

这是我的源代码:

<?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="match_parent"
tools:context="com.huy9515gmail.helloworld.MainActivity"
tools:layout_editor_absoluteY="81dp"
tools:layout_editor_absoluteX="0dp">


<Button
    android:id="@+id/button10"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="0"
    tools:layout_editor_absoluteX="87dp"
    tools:layout_editor_absoluteY="186dp" />

<Button
    android:id="@+id/button7"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="7"
    tools:layout_editor_absoluteX="34dp"
    tools:layout_editor_absoluteY="141dp" />

<Button
    android:id="@+id/button8"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="8"
    tools:layout_editor_absoluteX="87dp"
    tools:layout_editor_absoluteY="141dp" />

<Button
    android:id="@+id/button9"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="9"
    tools:layout_editor_absoluteX="140dp"
    tools:layout_editor_absoluteY="141dp" />

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="My First Calculator"
    tools:layout_editor_absoluteX="134dp"
    tools:layout_editor_absoluteY="16dp" />

<Button
    android:id="@+id/button"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="2"
    tools:layout_editor_absoluteX="87dp"
    tools:layout_editor_absoluteY="51dp" />

<Button
    android:id="@+id/button3"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="3"
    tools:layout_editor_absoluteX="140dp"
    tools:layout_editor_absoluteY="51dp" />

<Button
    android:id="@+id/button4"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="/"
    tools:layout_editor_absoluteX="281dp"
    tools:layout_editor_absoluteY="96dp" />

<Button
    android:id="@+id/button14"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="x"
    tools:layout_editor_absoluteX="228dp"
    tools:layout_editor_absoluteY="96dp" />

<Button
    android:id="@+id/button13"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="-"
    tools:layout_editor_absoluteX="281dp"
    tools:layout_editor_absoluteY="51dp" />

<Button
    android:id="@+id/button12"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="+"
    tools:layout_editor_absoluteX="228dp"
    tools:layout_editor_absoluteY="51dp" />

<Button
    android:id="@+id/button11"
    android:layout_width="106dp"
    android:layout_height="40dp"
    android:text="Delete"
    tools:layout_editor_absoluteX="228dp"
    tools:layout_editor_absoluteY="210dp" />

<Button
    android:id="@+id/button16"
    android:layout_width="106dp"
    android:layout_height="40dp"
    android:text="Calculate"
    tools:layout_editor_absoluteX="228dp"
    tools:layout_editor_absoluteY="170dp" />

<Button
    android:id="@+id/button15"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="1"
    tools:layout_editor_absoluteX="34dp"
    tools:layout_editor_absoluteY="51dp" />

<Button
    android:id="@+id/button2"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="4"
    tools:layout_editor_absoluteX="34dp"
    tools:layout_editor_absoluteY="96dp" />

<Button
    android:id="@+id/button5"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="5"
    tools:layout_editor_absoluteX="87dp"
    tools:layout_editor_absoluteY="96dp" />

<Button
    android:id="@+id/button6"
    android:layout_width="53dp"
    android:layout_height="45dp"
    android:text="6"
    tools:layout_editor_absoluteX="140dp"
    tools:layout_editor_absoluteY="96dp" />

<EditText
    android:id="@+id/editText"
    android:layout_width="310dp"
    android:layout_height="98dp"
    android:ems="10"
    android:inputType="textPersonName"
    tools:layout_editor_absoluteX="37dp"
    tools:layout_editor_absoluteY="327dp" />

None 的视图受到限制,尽管它们都有设计时位置。看看这个documentation regarding run-time constraints. This也是不错的介绍

设计时位置是这样的:

tools:layout_editor_absoluteY="81dp"
tools:layout_editor_absoluteX="0dp"

此代码将在设计器中定位您的视图。 运行-时间限制是这样的:

app:layout_constraintBottom_toBottomOf=”@+id/constraintLayout”
app:layout_constraintEnd_toStartOf=”@+id/imageView” 
app:layout_constraintStart_toStartOf=”@+id/constraintLayout”

并会在 运行 时间定位您的视图(以及在设计器中。)

不幸的是,当您推断约束时,发生了一些不好的事情。设计师做出了最好的猜测,但这不是我们想要的。

我建议您逐个查看布局,删除设计时约束并添加 运行 时间约束,直到您的布局看起来像您想要的那样。

硬编码值是在您“推断约束”时出现的。我建议您删除所有布局并重新开始,了解约束布局的工作原理。如果您看到“此视图不受约束”错误,Android Studio 告诉您的是:视图需要更多约束。

记住 iOS 上的 AutoLayout 和 Android 上的 ConstraintLayout(两者)的核心规则:每个视图都需要知道将自己定位在哪里(水平和垂直)并且它还需要知道它的大小又是什么,宽度和高度。

所以,想想你的布局……我给你举个例子。

从顶部开始,您希望“标签”与文本“欢迎使用我的计算器”居中。

很好,现在引擎需要知道 4 件事:

  1. 我应该把这个标签放在 X 轴的什么地方?
  2. 我应该把这个标签放在 Y 轴的哪个位置?
  3. 这个标签的宽度是多少?
  4. 这个标签的高度是多少?

有一些方法可以让引擎推断其中的一些(正如我们将要看到的),但对于大多数情况,您需要 这四个,per view(不管是推断的还是显式的)。

那么让我们从你的“标题”开始吧。

TextView 将居中,但我确定您希望它跨越它能找到的所有宽度(并在需要时压缩)。由于 ConstraintLayout 没有 match_parent(原因很明显:a.k.a。:这个想法是你必须设置约束),我们必须能够以不同的方式来做……

对于 X 轴(水平),我们希望将 textView 固定到 parentstart(又名:本例中的根),以及 end 的 parent (有效地使用所有屏幕,减去您决定在任一侧添加的任何边距)。

到目前为止,有两个约束。为了使上面的工作正常,ConstraintLayout 说你必须在 width 中使用 0dp 的“特殊”值。这告诉引擎宽度将是“我还不知道的任何值,在我计算完所有约束后我会知道”。

很好。现在我们已经解决了#1 和#3。

对于#2 和#4,你可以做类似的事情......或者你可以享受一些观点具有推断值的事实。例如:文本视图不需要高度,它们将根据字体大小、字符数等 auto-size,但您仍然需要告诉它文本视图在 Y 轴的哪个位置会去的

对于您的情况,我只是将文本视图的 top 与您的 parent.top 对齐。请注意,您不需要告诉布局将文本的 bottom 固定到任何内容,因为它的高度 = wrap_content.

等等……

现在转到 the official docs 并开始阅读有关您可以做的事情的更多信息(例如,锁链在这里可能会派上用场)。