ConstraintLayout之Barrier

时间:2024-04-06 11:11:46

泡在网上的日子 / 文 发表于2017-10-17 11:41 第5945次阅读 ConstraintLayout,转载网址http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/1017/8601.html

ConstraintLayout 的Barrier是1.1版本引入的一个非常实用的功能,但是官网没有对它做任何介绍,只提了一下名字:https://androidstudio.googleblog.com/2017/05/constraintlayout-110-beta-1-release.html 。

更正:官网还对Barrier这个类做了一些介绍:https://developer.android.com/reference/android/support/constraint/Barrier.html

它跟 Guideline  一样属于Virtual Helper objects,在运行时的界面上看不到,但是要比Guideline实用多了。

constraintlayout网站(非官方)对它的介绍已经非常清晰了:https://constraintlayout.github.io/basics/barriers.html 

下面是翻译:

当我们创建布局的时候,有时会遇到布局会随着本地化变化的情况,下面是一个简单的例子:

ConstraintLayout之Barrier

我们有三个TextViews: 左边 textView1 和 textView2 ,右边 textView3。textView3 约束在 textView1 的右边,效果也符合我们的预期。

但是当需要支持多语言的时候事情就变得复杂了。如果我们添加德语就出现了问题,因为在英语里面textView1的文字是长于textView2的,但是在德语中却是textView2的文字比textView1长:

ConstraintLayout之Barrier

这里的问题在于textView3仍然是相对于textView1的,所以textView2直接插入了textView3中。在设计视图里看起来更明显(白色背景的那个)。

比较直接的解决办法是使用TableLayout,或者把 textView1 & textView2 包裹在一个垂直的,android:layout_width="wrap_content" 的 LinearLayout中。然后让textView3约束在这个LinearLayout的后面。但是我们有更好的办法:Barriers。

Barrier 是一个虚拟视图,类似于 Guideline,用来约束对象。Barrier 和 Guideline 的区别在于它是由多个 view 的大小决定的。在这个例子中,我们不知道 textView1 和 textView2 哪个长些,因此我们可以 基于这两个 view 的宽度创建一个Barrier。我们可以让 textView3 约束在 Barrier 后面。

在编辑器中创建Barriers

首先选择上下文菜单的create a vertical barrier,创建一个垂直的barrier:

注:Android Studio2.3貌似没有这个菜单,Android Studio3.0有,但是在help菜单组的下级菜单,跟下面的演示图有些区别。

ConstraintLayout之Barrier

你可以在组建树(component tree)中看到Barrier(左边靠近底部的面板)。

我们可以通过拖动改变它的位置(可选项):

ConstraintLayout之Barrier

接下来我们需要设置Barrier 方向(direction)。这里我们是想让Barrier根据textView1 和 textView2 的大小确定是在谁的后面,因此我们需要把 direction 设置为 end:

ConstraintLayout之Barrier

最后一步是告诉Barrier它是相对于哪些view。我不用约束来形容是因为约束一般指一对一的,而这里是多个view。我们需要为 Barrier 指定引用的view的 ID , 可以通过在 component tree 中把view拖动到 Barrier 来完成:

ConstraintLayout之Barrier

一旦定义好之后,这些引用将被列为 Barrier 的 children。而且你还会在蓝色面板中看到Barrier跳到了新的位置(垂直的虚线)。

现在 Barrier 就已经定义好了,只剩下把textView3的约束从相对于 textView1 改为 相对于 Barrier 了:

ConstraintLayout之Barrier

完了之后 textView3 就到了 textView2 的后面了。

为了看到整体的效果,可以切换语言,此时你会看到 Barrier 会自动位于较宽的那个 textView 后面,也就间接让 textView3 也位于了正确的位置:

ConstraintLayout之Barrier

在XML中创建Barriers

XML代码其实也非常简单:

 
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.constraint.ConstraintLayout 
  3.   xmlns:android="http://schemas.android.com/apk/res/android"
  4.   xmlns:app="http://schemas.android.com/apk/res-auto"
  5.   android:layout_width="match_parent"
  6.   android:layout_height="match_parent">
  7.  
  8.   <TextView
  9.     android:id="@+id/textView1"
  10.     android:layout_width="wrap_content"
  11.     android:layout_height="wrap_content"
  12.     android:layout_marginStart="16dp"
  13.     android:layout_marginTop="16dp"
  14.     android:text="@string/warehouse"
  15.     app:layout_constraintStart_toStartOf="parent"
  16.     app:layout_constraintTop_toTopOf="parent" />
  17.  
  18.   <TextView
  19.     android:id="@+id/textView2"
  20.     android:layout_width="wrap_content"
  21.     android:layout_height="wrap_content"
  22.     android:layout_marginStart="16dp"
  23.     android:layout_marginTop="8dp"
  24.     android:text="@string/hospital"
  25.     app:layout_constraintStart_toStartOf="parent"
  26.     app:layout_constraintTop_toBottomOf="@+id/textView1" />
  27.  
  28.   <android.support.constraint.Barrier
  29.     android:id="@+id/barrier7"
  30.     android:layout_width="wrap_content"
  31.     android:layout_height="wrap_content"
  32.     app:barrierDirection="end"
  33.     app:constraint_referenced_ids="textView2,textView1" />
  34.  
  35.   <TextView
  36.     android:id="@+id/textView3"
  37.     android:layout_width="0dp"
  38.     android:layout_height="wrap_content"
  39.     android:layout_marginStart="8dp"
  40.     android:text="@string/lorem_ipsum"
  41.     app:layout_constraintStart_toEndOf="@+id/barrier7"
  42.     app:layout_constraintTop_toTopOf="parent" />
  43.  
  44. </android.support.constraint.ConstraintLayout>

Barrier特别的地方就在于Barrier元素自身。app:barrierDirection 属性决定 Barrier 的方向 - 这里把它放在被引用view的后面。被引用的view 是布局中的view的id列表,用逗号隔开。