27
2017
09

Android进阶——实战使用ConstraintLayout 替代LinearLayout、RelativeLayout和PercentLayout

引言

前面一篇文章Android 入门——ConstraintLayout详解以及使用替代你的常规布局总结了关于约束布局ConstraintLayout的一些基本知识和语法支持,理论上ConstraintLayout 可以替代很多常规布局组件快速实现相同的效果,尤其是在使用LinearLayout、RelativeLayout、PercentLayout需要进行N层嵌套的才能实现的时候,使用约束布局ConstraintLayout就明显可以减少布局层次的嵌套,接下来就让我们进入实战。

一、ConstraintLayout 替代LinearLayout

1、实现LinearLayout 中的浮动对齐特性

LinearLayout最基本的特性就是能让其子View在水平或者垂直方向浮动对齐。使用ConstraintLayout 在编辑器中通过手动拖动控件就可以实现——只需将下一个子View的上边沿(左边沿)添加约束到上一个子View的下边沿(右边沿),如下图实现相同的垂直方向浮动对齐,就是添加 View 然后将每一个 View 的上边沿添加约束向到它位置上的另一个 View 即可
这里写图片描述

2、ConstraintLayout 浮动特性的本质属性

XML 中实现该特性也仅仅是为每一个 View 实现一个约束属性 app:layout_constraintTop_toBottomOf 到整个浮动布局中在它之前的 View。

<?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=".MainActivity">

  <TextView  android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="16dp" tools:text="TextView" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" />

  <TextView  android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="8dp" tools:text="TextView" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView1" />

  <TextView  android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="8dp" tools:text="TextView" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView2" />

  <TextView  android:id="@+id/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="8dp" tools:text="TextView" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView3" />
</android.support.constraint.ConstraintLayout>

3、ConstraintLayout实现LinearLayout的权重weight 特性

ConstraintLayout实现权重主要是通过约束链(详见Android 入门——ConstraintLayout详解以及使用替代你的常规布局)。
这里写图片描述
当Constraint Chain 约束链创建完成后,还可以在属性视图中为每个需要设置 weight 权重的链组件修改 layout_width 为 match_constraint 或者 0dp (两者是一样的),然后再设置对应的权重值到 weight 的配置属性,因为这个例子中我们使用的是水平的 Chain 链,所以设置权重的时候设置的属性是 horizontal_weight,如下图。
这里写图片描述
设置horizontal_weight本质上就是和线性布局的权重作用,最终效果如下
这里写图片描述
最后要实现上图的效果,通过代码也可以实现,设置对应textView3的 android:layout_width=”0dp” and app:layout_constraintHorizontal_weight=”1”

<?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.stylingandroid.scratch.MainActivity">

  <TextView  android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="16dp" app:layout_constraintEnd_toStartOf="@+id/textView2" app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:text="TextView" />

  <TextView  android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintEnd_toStartOf="@+id/textView3" app:layout_constraintStart_toEndOf="@+id/textView" app:layout_constraintTop_toTopOf="parent" tools:layout_editor_absoluteX="141dp" tools:text="TextView" />

  <TextView  android:id="@+id/textView3" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginTop="16dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_weight="1" app:layout_constraintStart_toEndOf="@+id/textView2" app:layout_constraintTop_toTopOf="parent" tools:text="TextView" />

</android.support.constraint.ConstraintLayout>

其中, app:layout_constraintHorizontal_weight 属性设置的值与 LinearLayout 中设置的 android:layout_weight 是一样的值并且用法一样,将会根据所有子组件的设置的权重比分割剩余的空间

二、ConstraintLayout 替代RelativeLayout

RelativeLayout 最基本特性就是可以快速实现子 View 组件之间的布局相对关系或与父组件的相对关系来布局,简而言之就是以其中一个为参照物,另一个View在其位置基础上布局。从一定程度上说,ConstraintLayout 是升级版的RelativeLayout。

1、实现RelativeLayout的对应依赖关系

如下图创建Button始终位于TextView之上的布局,只需要把Button的下边沿约束指向TextView上边沿即可。
这里写图片描述

2、RelativeLayout属性对应ConstraintLayout 属性

由于ConstraintLayout 一定程度上可以看成是升级版的RelativeLayout,所以ConstraintLayout 中的部分属性是与RelativeLayout的部分属性一一对应的即实现相同的效果。

  • 相对于父组件的对应关系属性

这里写图片描述

值得注意的是:相对父组件的居中没有一对一的属性对应,即在ConstraintLayout中只用一条属性能实现同样居中效果的,而是通过设置相同的约束条件到相对的两个边缘来实现。同理其他方向的居中,水平居中,意味着需要设置两个相同的约束条件到水平的左和友边缘对齐父组件,而垂直居中,则是需要设置两个相同的约束条件到垂直的上下边缘对齐父组件,自然而然的在两个方向上都居中的话,则是需要设置两对相同的约束条件在水平和垂直方向,即是四个约束条件对齐。最后,在这里可以通过设置约束条件的 bias 来设置 View 组件垂直或水平对齐到父组件的百分比位置,如下图所示:
这里写图片描述

  • 相对于其他子View的边沿和基线的属性

这里写图片描述

三、ConstraintLayout对于 GONE的子View的处理

在RelativeLayout 能实现的属性中,ConstraintLayout 没有实现类似效果的属性只有一个 android:layout_alignWithParentIfMissing ,在RelativeLayout中这个属性将会让 子View能够在对齐对象不显示 (GONE)的时候,自动对齐到父组件。假如说子View A需要设置左对齐到toRightOf另一个子View B,当B不显示的时候,就会左边对齐到父组件,而ConstraintLayout 在这点上跟RelativeLayout 或者说大多数布局都不同,它会考虑显示为 GONE 的组件的位置并且针对不显示任何东西的 View 的约束 Constraint 仍然有效。但一旦视图变成GONE,在Constraint Layout中它的宽度和高度都被固定为0dp,并且它们的外边距被忽略。,为了解决这个缺陷,ConstraintLayout提供了对应的属性——layout_goneMargin [Left | Start | Top | Right | End | Bottom]来给子View指定边距,并且把约束添加到GONE的子View上。如下图所示,当按钮 GONE的时候,原本存在于输入框对按钮的属性 start_toEndOf 的 24dp 的外边距启用了另一个属性 app:layout_marginGoneStart=”56dp”
这里写图片描述

四、ConstraintLayout 替代PercentLayout

PercentLayout是一种响应式布局,主要特性就是把子View的大小设置为父布局大小的百分比。

1、将子View的宽度或高度指定为父级的百分比

在 PercentLayout 中是通过属性 app:layout_widthPercent 和 app:layout_heightPercent 来实现的。而在ConstraintLayout中是通过GuideLine和约束结合使用实现的,比如说要实现子View 占父布局的25%,首先我们得创建一个GuideLine并移动到25%处
这里写图片描述
然后给子View创建对应的约束,将子View约束在父级的开始边沿和GuideLine之间,(没有使用 left 而使用 start 是为了更友好的支持 RTL (从右到左布局,right to left),同时还需要设置android:layout_width 是被设置成了 0dp 或者 match_constraint,最后移除这个 View 的外边距子View 的宽度就会自动设置成父组件的 25%
这里写图片描述

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

  <android.support.constraint.Guideline  android:id="@+id/guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.25" />

  <TextView  android:id="@+id/textView3" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="0dp" android:layout_marginStart="0dp" tools:text="TextView" app:layout_constraintEnd_toStartOf="@+id/guideline" app:layout_constraintStart_toStartOf="parent" />

</android.support.constraint.ConstraintLayout>

本质上是通过GuideLine来实现的,百分比宽的 子View 只是创建了一个约束到参照线 Guideline就能实现固定的百分比宽高。

2、将子View的外边距设置为父组件的百分比

PercentLayout 还可以让我们实现相对于父组件的百分比外边距,同样的ConstraintLayout也可以通过GuideLine和约束结合使用来实现 。相对于上面百分比宽高的例子,我们一样需要在指定百分比位置设置一个 Guideline,但不是设置 View 的宽度约束到Guideline,而是设置 View 的 start 边缘约束到Guideline。假如我们需要设置的效果是 app:layout_marginStartPercent=”25%” ,我们创建一个在 25% 位置的Guideline,然后设置 View 的 start 边缘约束到Guideline,如下图所示:
这里写图片描述
在这个例子中我们还得设置这个 View 的宽度 android:layout_width=”wrap_content” ,然后移除各个方向的外边距 margin ,然后 View 就会有相对于父组件的 25% 宽度外边距 margin。

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

  <android.support.constraint.Guideline  android:id="@+id/guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.25" />

  <TextView  android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="0dp" app:layout_constraintStart_toStartOf="@+id/guideline" tools:text="TextView" />

</android.support.constraint.ConstraintLayout>

子View 如何设置约束到这个参照线,在这个例子,我们需要设置 app:layout_constraintStart_toStartOf=”@+id/guideline” 然后如上面编辑器中说的一样设置 android:layout_width 为 wrap_content 和 android:layout_marginStart 为 0dp

3、实现子View的固定横纵比

PercentLayout 中还有一个特性就是:支持固定的横纵(宽高)比,可以让子View的宽度和高度保持固定比例,当然 ConstraintLayout也可以快速实现,具体参见Android 入门——ConstraintLayout详解以及使用替代你的常规布局 假如说我们实现这个特性(即固定的宽高比),首先必须把这个 子View 的宽(android:layout_width)高(android:layout_height)为 match_constraint 或 0dp
这里写图片描述
然后我们在编辑器界面分别设置好水平方向边沿的约束,需要至少保留一个垂直方向的约束不设置,此时我们的子 View 高度就会是依赖于宽度(按照15:9的比例计算),最后通过移动参照线来缩放 View 的宽度的时候就会发现高度也会相应的根据函数变化。
这里写图片描述

4、直接在对应的XML代码实现子View的固定横纵比

在 XML 中,真正设置了宽高比的属性是 app:layout_constraintDimensionRatio

 <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.stylingandroid.scratch.MainActivity">

    <View
      android:id="@+id/imageView"
      android:layout_width="0dp"
      android:layout_height="0dp"
      android:layout_marginStart="16dp"
      android:layout_marginTop="16dp"
      app:layout_constraintDimensionRatio="h,15:9"
      app:layout_constraintEnd_toStartOf="@+id/guideline"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />

    <android.support.constraint.Guideline
      android:id="@+id/guideline"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:orientation="vertical"
      app:layout_constraintGuide_percent="0.39" />

  </android.support.constraint.ConstraintLayout>

译自:ConstraintLayout

上一篇:Android体系结构 下一篇:springmvc 异步请求(json + ajax + jquery)