LinearLayout

浮动对齐特性

LinearLayout的基本用法就是将子组件 View 在水平或者垂直方向浮动对齐,基于属性orientation来设置。在视图编辑器中使用 ConstraintLayout 要实现这个特性非常简单,假如要实现相同的垂直方向浮动对齐,步骤很简单,就是添加 View 然后将每一个 View 的上边缘添加约束向到它位置上的另一个 View 即可,如下图:

在 XML 中实现浮动对齐特性

在 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>

子组件权重特性

要想创建跟 LinearLayout 类似的 weight 权重特性的话,我们需要创建约束 Chain 链,详细可以看看我的另一篇文章,表现如下图:

Chain 链创建后,我们只需要在属性视图中为每个需要设置 weight 权重的链组件修改layout_widthmatch_constraint或者0dp(两者是一样的),然后再设置对应的权重值到weight的配置属性,因为这个例子中我们使用的是水平的 Chain 链,所以设置权重的时候设置的属性是horizontal_weight,如下图。

最后,我们就可以再 blueprint 蓝图视图下看到如下的展现:

在 XML 中实现权重特性

首先要如之前的教程一样,在 XML 创建 Chain 链,然后实现如上的效果只需要对textView3修改属性android:layout_width="0dp"并且设置新属性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是一样的值并且用法一样,将会根据所有子组件的设置的权重比分割剩余的空间。

RelativeLayout

RelativeLayout主要被用于包装布局根据 views 组件之间的关系或与父组件的关系来布局的子 views 。其实如果你对RelativeLayoutConstraintLayout都熟悉的话,就会感觉RelativeLayout其实只是ConstraintLayout的更基础版本,ConstraintLayout的很多概念来源其实就是RelativeLayout。事实上,你还可以认为ConstraintLayout就是加强版的RelativeLayout,因为你对旧的 Android 布局组件的熟悉,这将是很好的学习了解ConstraintLayout的思想体系模型。

在视图编辑器中实现 RelativeLayout

因为RelativeLayout就是基于描述各个子 Views 之间的关系,而对各个子 Views 添加约束来实现相同的关系以及展现其实也很相似简易实现。举例,创建布局“ X 位于 Y 之上”的约束就对应于RelativeLayout中的android:layout_above属性:

相似效果的属性对应表

上面已经提到了RelativeLayoutConstraintLayout的基本特性概念非常相似。你可以通过查阅我的另一篇文章来熟悉ConstraintLayout的基础,然后使用如下面的表格中对应的属性来转换RelativeLayout中的属性到ConstraintLayout

相对父组件

RelativeLayout ConstraintLayout
android:layout_alignParentLeft="true" app:layout_constraintLeft_toLeftOf="parent"
android:layout_alignParentLeft="true" app:layout_constraintLeft_toLeftOf="parent"
android:layout_alignParentStart="true" app:layout_constraintStart_toStartOf="parent"
android:layout_alignParentTop="true" app:layout_constraintTop_toTopOf="parent"
android:layout_alignParentRight="true" app:layout_constraintRight_toRightOf="parent"
android:layout_alignParentEnd="true" app:layout_constraintEnd_toEndOf="parent"
android:layout_alignParentBottom="true" app:layout_constraintBottom_toBottomOf="parent"
android:layout_centerHorizontal="true" app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"
android:layout_centerVertical="true" app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"
android:layout_centerInParent="true" app:layout_constraintStart_toStartOf="parent",app:layout_constraintTop_toTopOf="parent",app:layout_constraintEnd_toEndOf="parent", 和app:layout_constraintBottom_toBottomOf="parent"

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

对齐到其他 View 组件边缘或者基线

RelativeLayout ConstraintLayout
android:layout_toLeftOf app:layout_constraintRight_toLeftOf
android:layout_toStartOf app:layout_constraintEnd_toStartOf
android:layout_above app:layout_constraintBottom_toTopOf
android:layout_toRightOf app:layout_constraintLeft_toRightOf
android:layout_toEndOf app:layout_constraintStart_toEndOf
android:layout_below app:layout_constraintTop_toBottomOf
android:layout_alignLeft app:layout_constraintLeft_toLeftOf
android:layout_alignStart app:layout_constraintStart_toStartOf
android:layout_alignTop app:layout_constraintTop_toTopOf
android:layout_alignRight app:layout_constraintRight_toRightOf
android:layout_alignEnd app:layout_constraintEnd_toEndOf
android:layout_alignBottom app:layout_constraintBottom_toBottomOf
android:layout_alignBaseline app:layout_constraintBaseline_toBaselineOf

这里提醒一下大家,很多ConstraintLayout能够实现的约束条件在RelativeLayout中不能实现,比如对齐 View 的基线到另一个 View 的上或者下边缘。之所以没有列出来也是因为RelativeLayout中并没有相对应的属性实现。

Constraint 约束对于不显示的GONEViews

RelativeLayout实现的属性中,ConstraintLayout没有实现的属性只有一个android:layout_alignWithParentIfMissing,这个属性将会让 View 组件能够在对齐对象不显示GONE的时候,对齐到父组件。举个例子,如果 A View 需要设置左对齐到toRightOf另一个 View (这个就命名为 B ) ,当B不显示的时候,就会左边对齐到父组件。

ConstraintLayout在这点上跟RelativeLayout或者说大多数布局都不同,它会考虑显示为GONE的组件的位置并且针对不显示任何东西的 View 的约束 Constraint 仍然有效。唯一的缺陷是这个GONE的 View 的宽高是 0,而且外边距 margin 也被忽略不考虑。

为了适应这种场景的情况下,ConstraintLayout拥有一个属性app:layout_goneMargin[Left|Start|Top|Right|End|Bottom]可以用于当约束对象是一个GONEView 的时候,设置外边距 margin 。在下面的例子中,当按钮消失 gone 的时候,原本存在于输入框对按钮的属性start_toEndOf24dp的外边距启用了另一个属性app:layout_marginGoneStart="56dp",如下动态图所示:

PercentLayout

PercentLayout通常被用于响应式布局设计,当需要根据父组件来缩放子组件到百分比的情况。

相对父组件的百分比宽高

首先我们要看的特性是,子组件要实现占据父组件的宽度或者高度的固定百分比。它在PercentLayout中是通过属性app:layout_widthPercentapp:layout_heightPercent来实现的(此处的命名空间 app 是因为 PercentLayout 的库引入是来自于 support library)。要实现该特性的话,我们可以通过ConstraintLayout中的 Guidelines 参照线来实现。假如我们需要实现app:layout_widthPercent="25%"的特性,我们可以首先创建一个参照线,移动到25%处:

然后我们就需要创建一个 View 将它的创建约束到父组件的start边缘以及end约束到参照线。在此处,我们没有使用left而使用start是为了更友好的支持 RTL 语言(从右到左布局,right to left)

同时,我们还需要注意的是我们需要设置android:layout_width是被设置成了0dp或者match_constraint(源码层面,他们是一样的)。然后移除这个 View 的外边距,那么这个 View 的宽度就会自动设置成父组件的25%,进一步操作如下图所示:

在 XML 中实现百分比宽高

以上例子的 XML 源码如下:

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

实际上真正对齐百分比宽高是由 Guidline 完成的,百分比宽的 TextView 只是创建了一个约束到参照线 Guideline就能实现固定的百分比宽高。

相对父组件的百分比外边距 margin

PercentLayout还可以让我们实现相对于父组件的百分比外边距 margin 。相比上面百分比宽高的例子,我们一样需要在指定百分比位置设置一个 Guideline参照线,但不是设置 View 的宽度约束到参照线,而是设置 View 的start边缘约束到参照线。举个例子,如果我们需要设置的效果是app:layout_marginStartPercent="25%",我们创建一个在25%位置的参照线,然后设置 View 的start边缘约束到参照线,如下图所示:

然后,在这个例子中我们还设置这个 View 的宽度android:layout_width="wrap_content",然后移除各个方向的外边距 margin ,然后 View 就会有相对于父组件的 25% 宽度外边距 margin。

在 XML 中实现百分比外边距

在 XML 中,参照线 Guidline 是跟上面的例子一样的设置,如下:

<
?
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_widthwrap_contentandroid:layout_marginStart0dp

实现固定横纵比布局

最后一个特性就是实现PercentLayout的横纵比特性,通过它可以让高度固定比例为宽度的函数,或者反过来。关于ConstraintLayout如何实现横纵比尺寸,我有另一篇文章更详细的讲解了这个特性。首先我们设置一个固定的比例,然后设置这个 View 的宽高为match_constraint0dp

然后我们设置好水平方向的两个约束条件,然后至少保留一个垂直方向的约束不设置,那么我们的组件 View 高度就会是依赖于宽度的函数,然后通过移动参照线来缩放 View 的宽度的时候就会发现高度也会相应的根据函数变化。

在 XML 中设置横纵比布局

在 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基础系列之尺寸横纵比 dimensions

results matching ""

    No results matching ""