ConstraintLayout(约束布局) part 1

来源:互联网 发布:尚学堂高淇java怎么样 编辑:程序博客网 时间:2024/06/05 11:39
ConstraintLayout 和它的布局编辑器将会在不久之后推出. 这篇文章所讲述的关于约束布局的内容是基于 constraint-layout:1.0.0-alpha4. 它的一些行为最终在正式推出时可能发生些许改变。
Google I/O 2016开发者大会宣布了一个新的安卓布局工具和支持库。 Android Studio 将会装备一个基于约束的可视化编辑器, 和新的ConstraintLayout 容器用以在运行时解释这些约束.
该文章旨在检查 ConstraintLayout容器的结构和工作原理. 未来,新的Android Studio 布局编辑器将会使它更加强大和灵活和易于管理该类布局. 通过更加深入的了解 ConstraintLayout,我们将会更好的了解我们的开发工具。
ConstraintLayout 被分配到了一个未绑定的支持库(support library)中 , 因此在该文中你将会看到许多的xml属性以 app:开头而不是 android: 
让我们首先定义什么是约束( constraint) 

约束类型(Types of Constraints)

从谷歌放出的相关包链接中可知,视图(view)上的约束是指 “描述一个在屏幕上的view与布局中其它元素之间的位置关系.” 更简单的说, 约束将view上的点(称之为锚点  anchor points)和目标(target )之间联系了起来.  target 可以是:
  • 同级视图上的相关锚点

  • 父容器的相关锚点

  • 一条基线(稍后介绍)

每个view 支持如下锚点作为它们约束中的源(source)或目标(target):
  • Top, Bottom, Left, and Right (or Start and End)

  • CenterX and CenterY

  • 基线

在xml中,约束表现为如下形式:
layout_constraint[源锚点]_[目标锚点]="[目标ID]"
例如, 定义一个约束在 @id/button_cancel 的末尾和@id/button_next 的开始之间 ,如下所示:
<Button
android:id="@+id/button_cancel"
/>
 
<Button
android:id="@+id/button_next"
app:layout_constraintStart_toEndOf="@+id/button_cancel"
/>
在可视化布局编辑器中,当你使用带箭头的线来描述两个view之间的约束时, 工具会自动的在xml文件中加入这条线. 这有一个更加完整的ConstraintLayout XML示例:
<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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
 
<Button
android:id="@+id/button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/constraintLayout"
android:layout_marginStart="16dp"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
android:layout_marginBottom="16dp" />
 
<Button
android:id="@+id/button_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@+id/button_cancel"
android:layout_marginStart="16dp"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
android:layout_marginBottom="16dp"/>
 
</android.support.constraint.ConstraintLayout>

在该示例中, 我们定义了一些约束使得Button视图在父容器中排成了一列。如前面所说的,它们使用了相似的文字描述, 只不过目标的ID是ConstraintLayout .
约束语句经常通过 android:id来引用targets。如果在约束加进来之前你的视图还没有定义id,Android Studio 会根据你在约束中声明的id为你创建一个

在上面的案例中,你或许注意到了 ConstraintLayout 支持页边距(margins). 默认的, 两个视图之间的约束将会被解释为一个接一个的挨在一起.如果你想让你的视图之间留有空隙,那么margins是必须设置的。

它似乎很像 RelativeLayout 真是如此吗?

偏向约束(Biasing Constraints)

当一个view的所有方向都受限于对应的轴时(例如,上下对应的是垂直轴,左右对应的是水平轴),默认的它将会在两个目标的锚点之间留出空白, 下面的XML将一个按钮添加到了父容器的正中间:
<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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
 
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintStart_toStartOf="@+id/constraintLayout"
app:layout_constraintEnd_toEndOf="@+id/constraintLayout" />
 
</android.support.constraint.ConstraintLayout>

这对我们来说是个很好的表现,但是 ConstraintLayout 采取了一个叫做刻度的概念,称之为偏向(bias). Bias 支持用权重来描述约束中非平均分布的空隙,例如:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintStart_toStartOf="@+id/constraintLayout"
app:layout_constraintEnd_toEndOf="@+id/constraintLayout"
app:layout_constraintHorizontal_bias="0.25"
app:layout_constraintVertical_bias="0.25" />
 
</android.support.constraint.ConstraintLayout>
现在,上面的按钮按照权重为25/75 分割了每一个轴的可用空白区域. 这更加像是 LinearLayout 或 GridLayout.中的权重 ,但是比它们更好。因为view并没有填满可用的空白区域。
特别的, 当约束中么有出现bias时,bias 为 0.5. 这就是视图默认居中的原因了。
你一定很期望开始看的 ConstraintLayout 扁平化视图层次的能力。它可以表现得像任何现有的布局管理器布局一样,或者说它们的所有表现!

基线定锚(Anchoring to Guidelines)

有时候,为了对齐view,我们需要在一个地方有专门的锚点, ConstraintLayout 提供了基线(guidelines). 一个 Guideline 实际上是View的子类 并且和其它子类一样添加. Guidelines 有一些特别的地方:

  1. 它们的测量宽度永远为0

  2. 它们的可见性为不可见( View.GONE)

尽管它作为view存在于容器中,但他永远都不可见. 它的存在仅用于提供基线属性,为其它view定义水平或垂直的锚点. 请看一个示例:

<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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
 
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline"
android:orientation="vertical"
app:layout_constraintGuide_begin="72dp" />
 
<Button
android:id="@+id/button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintVertical_bias="0.25" />
 
<Button
android:id="@+id/button_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintVertical_bias="0.75" />
 
</android.support.constraint.ConstraintLayout>

一个垂直的基线被设置在距开始72dp 的位置. 每一个Button 现在可以使用该基线上的任意点作为它的 constraintStart 目标来排列对齐它们. Guidelines 可以有如下三个属性中的一个:

  • layout_constraintGuide_begin:从开始边算起的绝对距离

  • layout_constraintGuide_end:从结束边算起的结束距离

  • layout_constraintGuide_Percent: 从开始边算起的百分百布局

处理约束的角度看, 一个基线上的所有锚点(水平或垂直).都是有用的目标,同样的,要有一个ID 。

In the current alpha, 这里有个bug,如果view引用该基线在前,而基线view之后才定义在后,将导致约束无法正常工作。为了正常工作,经常先加基线(在可视化编辑器中)或者手动的加入到xml的前面。

view的测量(View Measurements)

上面已经谈到了许多关于view的定位问题.现在就来讨论一下view的大小问题 ConstraintLayout 支持一些你可能用到过的测量规则。 下面是关于子view的宽/高的三种测量规则:
  1. Exact: 一个精确的大小 (通常是给定的dp)

    • 设置layout_width 或layout_height 为 一个非零大小

  2. Wrap Content: 包裹 view’s内容

    • 设置layout_width 或 layout_height 为wrap_content

  3. Any Size: 根据相关的约束条件填充可用的空白

    • 设置layout_width 或layout_height 为0dp

那么, match_parent到哪里去了?! ConstraintLayout 并不支持它, 并且接下来我会解释原因. 最近的版本说 any size 有效的替代了 match parent 的使用场景,并且更好的支持了约束规则。

任何在可视化界面中试图给view添加match_parent 的操作将会被覆盖, 并且如果你在 XML中添加它 ,将会产生十分笨拙的结果,请不要使用它 。

使用any size, 我们可以告诉该view伸长到约束定义中的轴上. 或许一个例子更好理解?

<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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
 
<Button
android:id="@+id/button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/constraintLayout"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"/>
 
<Button
android:id="@+id/button_next"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@+id/button_cancel"
app:layout_constraintEnd_toEndOf="@+id/constraintLayout"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout" />
 
</android.support.constraint.ConstraintLayout>


通过设置 layout_width 为0dp, 第二个按钮填充了从右边界到第一个按钮end边界之间的空隙. 这和框架中的权重十分的相似, 但是更加的灵活和实用。

其它

UI布局第一个公共任务就是通过特定比例(aspect ratio)来测量view的大小  . 在图像(image)上用得十分频繁,无论它是矩形 (1:1), 4:316:9,或者其它自定义的形状。 使用ConstraintLayout, 你不必再创建创建自定义的View 或ViewGroup 子类,由于 layout_constraintDimensionRatio的存在。

该特征要求被关联的视图的尺寸"已知" (固定尺寸或 wrap_content) 并且另外的是“any size” (0dp).  “any size” 尺寸将会由规则中定义的比例来分配。

<?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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
 
<ImageView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:src="@drawable/water"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintLeft_toLeftOf="@+id/constraintLayout"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
app:layout_constraintRight_toRightOf="@+id/constraintLayout"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintVertical_bias="0.0" />
 
<ImageView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:src="@drawable/grass"
app:layout_constraintDimensionRatio="4:3"
app:layout_constraintLeft_toLeftOf="@+id/constraintLayout"
app:layout_constraintRight_toRightOf="@+id/constraintLayout"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout" />
 
 
</android.support.constraint.ConstraintLayout>


很遗憾,SquareImageView 和AspectImageView, 我们可能再也不需要你了


来源: http://wiresareobsolete.com/2016/07/constraintlayout-part-1/

0 0
原创粉丝点击