解析ConstraintLayout的constraintDimensionRatio属性

最近在学习ConstraintLayout时遇到这个属性用不太明白,网上找不到太多详细的资料,参考官网文档和自己的摸索后,把自己的结论跟大家分享下,欢迎批评指正。

首先来看一下官网的解释,如图

image

由文档我们首先能得出以下结论:

  1. 如果要使用这个属性,我们至少要把控件的宽或高中间的一个设置为match constraints,具体怎么设置就不再赘述(XML和View Inspector里都可以).
  2. ratio的比值表示的是宽高比,注意,一直都是宽高比

了解这两点之后,问题来了,系统是怎么知道我们究竟是"以宽为准,按比例去设置高"呢? 还是"以高为准,按比例去设置宽"呢?

我们首先注意到1.里所说的,必须把宽或者高其中之一设为match_constraint,而match_constraint的意思是满足约束。为什么要这么做呢?

举个例子,我们把layout_width设置为match_constraint, layout_height设为固定值100dp,那么很显然,高度是写死的,宽度是需要满足某种约束。此时,如果我们设置了layout_constraintDimensionRatio ="4:1",会出现什么效果呢?很显然,系统会保持高度为100dp,而宽度为高度的4倍,即400dp,从而“match_constraint”满足约束。下面我们来试验一下:

约束width, layout_width="0dp"

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"
    tools:context="com.example.xuqi.constraintlayoutdemo.MainActivity">

    <ImageView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_marginBottom="252dp"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="w,4:1"
        tools:layout_editor_absoluteX="5dp"
        android:background="@color/colorAccent"/>
</android.support.constraint.ConstraintLayout>

preview如下:

以高度为基础按比例设置宽度的示例

显然达到了我们的预期。


约束height,layout_height="0dp"

同理,如果我们把height设为match_constraint,width设为100dp,那么系统就认为我们要以width为准去约束height,我们再加上一句app:layout_constraintDimensionRatio="h,1:2",那么高就是宽的2倍

<?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.example.xuqi.constraintlayoutdemo.MainActivity">

    <ImageView
        android:id="@+id/textView"
        android:layout_width="100dp"
        android:layout_height="0dp"
        android:layout_marginBottom="252dp"
        android:background="@color/colorAccent"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="h,1:2"
        tools:layout_editor_absoluteX="5dp" />

</android.support.constraint.ConstraintLayout>

效果如下:

以宽度为基础按比例设置高度的示例

同时约束,layout_width="0dp" && layout_height="0dp"

想象一个场景,我们想在布局里放一张banner,宽度铺满全屏,高度始终为宽度的1/3。那么我们首先为了宽度铺满全屏,需要将width设为match_constraint,又因为高度需要跟宽度形成1:3的比例,所以高度也要同样设置match_constraint,然后将app:layout_constraintDimensionRatio设为"h,3: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.example.xuqi.constraintlayoutdemo.MainActivity">

    <ImageView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@color/colorAccent"
        android:text="TextView"
        app:layout_constraintDimensionRatio="h,3:1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        tools:layout_editor_absoluteY="0dp" />

</android.support.constraint.ConstraintLayout>

效果如下:

宽度为全屏,高度按比例设置的示例

h和w参数的解释

这里我们还需要解释一下app:layout_constraintDimensionRatio的值里面的h和w是什么意思。一般来说,加上h的意思就是,h之后的比例是以w为基础去设置h,即h = w * ratio。反之,写上w的意思是,w = h / ratio (因为 ratio = w / h 代表宽高比)。

以及,如图
image

英文好的同学可以直接看文档

我们可以看到,如果只把一条边设为0dp,那么我们是无需添加h和w的(会有默认值)。因为我们只能去通过未设为0dp的边来约束设为0dp的那条边,也就是说h和w就对应设为0dp的那条边。而如果两条边都设为0dp,那么就必须设置h和w了,不然系统不知道我们想约束哪条边。原理还是一样的,希望哪条边被约束,我们就写哪条边的字母。

总结

以上主要还是想告诉大家这个属性的原理,其实真正去用的时候还是用View Inspector来做的比较多。当我们把至少一条边设为match_constraint后,点击方框左上角的toggle按钮,可以设置对应的比例,方框里显示的横线或竖线表示哪条边是被限制,跟属性里的h和w是对应的。示例如下:

  1. layout_width = "0dp" && layout_height = "0dp"
实例1,点击toggle按钮可以切换约束的边,方框中有一条线横竖变换
  1. layout_height = "0dp"
实例2,只有height是0dp时,点击toggle按钮,方框里始终为竖线
  1. layout_width = "0dp"
实例3,只有weight是0dp时,点击toggle按钮,方框里始终为横线

推荐阅读更多精彩内容