冷门知识大疑惑系列:ConstrainLayout约束布局之宽高比之解惑

4,404 阅读7分钟

一、开门闲话

       首先写这篇文章之前,扯个淡,关于ConstrainLayout约束布局中的app:layout_constraintDimensionRatio 属性,今天我总算通过自己努力钻牛角尖,自己解了自己困扰多年的问题。 如果你还没用过,说明基础还不行啊,倒回去多写写UI咯~
哈哈,开个玩笑。

       废话少说,圆规正传。见名之义,它就是用来宽高约束的,这不废话么。 没错,废话也要说一遍。 虽然它只是一个布局属性,有人可能觉得很简单啊,写个比例完事了嘛。Really?如果你用过,你一定对这个属性会有和我以前一样的感觉和困惑之处 。

      用到的时候,试个几遍总能试出来。但是如果要靠试出来,那就是没有真正理解到位。 为什么不能下意识就配置正确 ?下面就开始为你,用最通俗易懂的话语,排忧解惑。

  • 总之,如果有疑惑,本文总结的内容,就是笔者辛苦实践后,独家揭秘,网上没有资料喔。值得一看。 - _ -

Tips:请耐心阅读。 想直接看结论的,可以直接跳最后。

二、雾里看花

  1. 什么时候用这个属性?
  2. 宽高比例约束怎么配置?如何去理解?
  3. 有了宽高比例约束,宽高属性值又如何配置?
  4. 既有宽高,又有约束如何理解?
  5. 如何快速去算?(也就是我总结的套路)

三、拨云见月

1 . 什么时候用这个属性?

当你布局一个控件,想按照一定比例去布局,但又不想写死具体值时。或者想要尽可能的适配不同的屏幕。
比如:你想要一个宽度充满屏幕,宽高相等1:1的控件?
常规布局是无法直接设置的。需要通过代码动态计算控件高度,设置高度=屏幕宽度

比如:你想要一个宽度100dp, 宽高又是16:9,或者1:10的控件?
插入动态代码计算,总之不好看

这时候就可以用上 app:layout_constraintDimensionRatio 属性。

2. 宽高比例如何配置?

通常情况下,配置宽高比时,宽高大小都会约束为0dp,约束到parent,进行铺满 android:layout_width="0dp" android:layout_height="100dp"

  • 语法如下:
    app:layout_constraintDimensionRatio="h,1:1"

   h -->> 前面写h的时候,需要反过来理解,以宽度 w 的值为基准参考值,根据比例去算 高度 h
w -->> 前面写w的时候,需要反过来理解,以宽度 h 的值为基准参考值,根据比例去算 宽度 w
1:1 -->> 表示宽高比。记住: 不管前面写h,还是w, 请一定要理解成 宽 :高

  • 如示例:h,1:1
    以宽度w为参考,计算高度。 并且按比例1:1。

    因为宽度是充满。那么高度就一定是宽度的值,呈正方形了。
    (约束布局下,宽度=0dp, start-parent, end-parent,就是match_parent)

企业微信截图_aef876d2-f403-42eb-affc-8b4f85891373.png

  • 再比如: 改为:w,1:1 。 宽、高均为0dp, 左右上下约束的是parent,也就是默认铺满
    结果就是以高度为参考值,按照比例 宽高1:1,计算宽度w.
    由图可以证实,宽度按照高度值已经超出屏幕之外

    企业微信截图_3417fe46-ebe2-49a2-9de8-8d0c47c3d9b7.png

啊? 就这?别急!上面只是一种很基础的配置。我们加上一点条件,再变化一下看看情况。

3.配置了宽高比例,同时单边却有固定值 ?

  • 比如:此时我的配置是
    android:layout_width="100dp"
    android:layout_height="0dp"
    app:layout_constraintDimensionRatio="h,1:10"
    请先自己脑袋想一下2秒,此时布局,这个控件应该是个什么样? 再往下看。

    --

答案:高度保持0dp充满,宽度为固定值100dp. 宽高比:1:10.
前面写的h,按照前面总结的, 以w宽度为参考值,计算高度h.
此时,宽度固定为了100dp, 宽:高=1:10, 那么高度为1000dp. 如图

企业微信截图_b7c1f2db-f167-478f-83c3-f9f89290dc67.png

--

  • 再变化一下,此时我的配置是
    android:layout_width="100dp"
    android:layout_height="0dp"
    app:layout_constraintDimensionRatio="w,1:10"
    将h,改为了w,请先自己脑袋想一下2秒,此时布局,这个控件应该长什么样? 再往下看。

--
诶,马老师说"婷婷,我要婷婷” ,这个时候可能你就有疑惑了?
按照前面总结的,前面是w, 就是按照高度h为基准值,计算高度值。
可是此时高度为0dp, 充满屏幕,按照宽:高=1:10. 计算高度? 这逻辑说不通啊,咋一边按照h值,一边又计算它自己!

重点来了,这种情况下, 三个步骤

  • 首先,如果某一边固定了具体的值,如100dp(0dp不算), 就是以该边为参考,求另一边。
  • 宽高约束比前的值和该边相同,则忽略,不同则按比例值求算。 示例:宽度=100dp, w,1:10, 那么还是以宽度为参考,求h。
  • 所求值(h)= 已知值 * 比例(1/10), h=10dp 。 如图

企业微信截图_f8512d09-bfc6-4c0d-a9c5-2ee2756f01af.png

--

  • 你理解了吗? 现在反过来。 给出单边固定高度h的情况。 来进行验证
    w=0dp h=100dp铺满, 宽高比: w,1:10.
    约束和固定边不同,则按照结论:以h为参考边,计算w的值
    并且: w=h / 比例(1/10)

企业微信截图_c62ac8c1-cba3-4c63-bc08-94103234d4cc.png

  • w=0dp h=100dp铺满, 宽高比: h,1:10.
    约束和固定边相同,则忽略结论:还是以固定边为参考边,计算w的值
    并且: w=h* 比例(1/10)

企业微信截图_ba017945-125c-4966-8959-cfdfc2b3765b.png

4. 同时具有宽高固定值,又配置了宽高约束

这样的情况,

  1. 配置宽高都为固定值,此时宽高约束会无效。会优先按照宽高固定值。
  2. 配置为wrap_content, 此时宽高比约束会无效,也是安卓宽高固定值(自适应)

企业微信截图_636afe49-b5be-4eef-9017-f460b2579f1e.png
企业微信截图_c2d86f2b-a0ec-4a55-8764-6ab830a2f1a2.png

5. 特殊情况:宽高比例配置,不写w或者h

  • 配置宽高比时,还可以省略 w或者h , 语法如: app:layout_constraintDimensionRatio="1:20"

  • 这种情况应该以哪边为参考值呢? 也许你会认为,默认就是h,或者w。 其实不是这样的。 系统会根据比例数字大的一边作为长边参考值。

    • 如 1:20 代表的是宽:高。20比1大,此时,就会以高度为参考值,去计算宽度。
    • 高度由于是0dp,铺满屏幕, 那么宽度就是高度的 1/20.
  <TextView
       android:layout_width="0dp"
       android:layout_height="0dp"
       android:text="这是被约束比例的控件"
       android:gravity="center"
       android:textSize="30sp"
       app:layout_constraintDimensionRatio="1:20"
       android:background="@color/colorPrimary"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintTop_toTopOf="parent"
       app:layout_constraintBottom_toBottomOf="parent"/>

企业微信截图_daf7d914-8809-4de5-b9da-2fa613acd305.png

--

  • 改为: app:layout_constraintDimensionRatio="20:1"
  • 20:1 代表的是宽:高。20比1大,此时,就会以宽度为参考值,去计算高度。
  • 宽度由于是0dp,铺满屏幕, 那么高度就是高度的 1/20

企业微信截图_38857eee-31c5-4094-b8b0-3cd6a874acf7.png

四、万变不离其宗

  • 总是套路得人心。 举了这么多例子,是时候推出 最后的总结了。 如果你已经看出规律了。那太好了。说明本文的作用达到了

套路公式

  • 宽高比属性值,写h时,求值时,采用 ➗ 比例。 如 :h, 1:10 x=y / (1/10)
  • 宽高比属性值,写w时,求值时,采用 * 比例。    如 :w,1:10 x=y * (1/10)
  • 但还得注意控件宽高属性值的配置。 见下图
  • 同时如果省略h,w时,优先采用数字大的一边 作为参考边

企业微信截图_81113f5e-48a4-4134-bf42-fb647648135c.png

五、结束语

   这里做个结束语吧,本文只是笔者的一点见解。 虽然该知识点很小,很不惹人注意。但是要弄懂搞明白,实属需要花些心思。至少目前我没有看到网上有相关详细解读。只是单纯告诉你这个宽高比,但是规则却没有任何解析。导致几年前在写该属性时,每次都需要花一定时间去试。却始终找不到规律的痛苦。