Android 机型适配之百分比适配 ConstraintLayout

由于Android的品类繁杂,机型适配向来是一个难题,常见的通过 LinearLayout + RelativeLayout 的方式进行适配具有较大的局限。而相比之下,百分比适配就强大很多了。

以往方式的弊端

  • RelativeLayout
  • 优点:相对布局,根据控件之间的相对关系互相依赖,使控件 位置 保持统一。
  • 缺点:无法保证控件 尺寸 的统一性。
  • LinearLayout
  • 优点:可通过权重布局,使控件 尺寸 保持统一。
  • 缺点:无法 灵活 设定控件的 位置 ,并且只能控制 单方向 尺寸 (横/竖)。
  • Dp
  • 优点:根据不同屏幕显示参数, 动态 计算值。
  • 缺点:无法做到 精确 控制,存在一定误差,且在极端情况下,无法适配。

百分比布局库

PercentLayout

Google官方提供的百分比布局库,包含 PercentFrameLayout PercentRelativeLayout 。version 24.1.0引入,version 26.1.0被弃用(真的短命)。

导入方法:

compile 'com.android.support:percent:26.1.0'

这也是最初本来准备尝试的库,因为不知道具体的使用方法于是去官网查文档,结果看到以下字段:

This class was deprecated in API level 26.1.0.
consider using ConstraintLayout and associated layouts instead. The following shows how to replicate the functionality of percentage layouts with a ConstraintLayout. The Guidelines are used to define each percentage break point, and then a Button view is stretched to fill the gap:

很无奈,刚准备学习一个新库,结果还没开始就已经被官方宣布寿终正寝。花了2秒感叹下生命周期的短暂,然后开始研究新库。想要参考下使用方法的可以点击官网进行阅读: PercentFrameLayout

ConstraintLayout

相对于 PercentLayout 来说ConstraintLayout享受的简直是亲儿子待遇,官方多次公开宣传过该控件,并配有视频等资源。

对我来说,只是在刚开始有了解过一些,最后判断该控件只是官方用来便于 图形化 搭建而诞生的,因此便没再过多研究。直到偶然机会发现这个布局竟然可以完成百分比布局的功能,所以才重新启用。

导入方法:

compile 'com.android.support.constraint:constraint-layout:1.1.0-beta5'

Constraint

ConstraintLayout的核心就两个字:约束。除了普通的参数外核心参数有:

layout_constraintLeft_toLeftOf
layout_constraintLeft_toRightOf
layout_constraintRight_toLeftOf
layout_constraintRight_toRightOf
layout_constraintTop_toTopOf
layout_constraintTop_toBottomOf
layout_constraintBottom_toTopOf
layout_constraintBottom_toBottomOf
layout_constraintBaseline_toBaselineOf
layout_constraintStart_toEndOf
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf

这些参数理解起来很容易,由两个位置组成,第一个代表当前控件,第二个代表目标控件。例如:

app:layout_constraintStart_toStartOf="parent" 
 控件左侧与父布局左侧建立约束
 app:layout_constraintTop_toBottomOf="@id/button"
 控件顶部与id为button的控件底部建立约束

建立了约束的两边就像是在之间安装了一个 强力的弹簧 ,如果没有别的“弹簧”与之进行力的平衡,控件就会被拉过去。详情请想象简单的物理受力平衡。不明白的直接动手写,然后在布局 Design 选项能直接看到对应的受力模型,可以说做得很直观了。

Layout

建立好约束之后,默认情况每个约束的“力”都是相同的,例如: ConstraintLayout 中有一个 button button 的四边分别约束了父布局的四边,就好像四条弹簧将 button 的四边和父布局的四边连起来了,因为弹簧的力是相同的,所以 button 最终的位置会在父布局的中央。如图:

android中的各种constrainlayout android constraintlayout百分比_控件

而实际上这个“力”是可以不同的,通过以下参数可以设置:

app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintVertical_bias="0.5"

参数值以百分比表示,简单说明,以上述例子,如果 app:layout_constraintVertical_bias="0.1" ,那么 button 整体 会处在父布局竖直百分之10的位置上。至于怎么去理解这个 整体处在 ,原谅我表达不是很好,不知道该怎么说,自己去体会吧。

通过调节这个参数便能以百分比的方式控制控件的所在位置了,实在是很方便。

Measure

主要分为三种:

WRAP_CONTENT
MATCH_PARENT
MATCH_CONSTRAINT

挨个说,前两个应该是无比熟悉了,使用效果和一般的没什么区别。重点是第三个,从名字上也能看出,由上面的 约束 所决定,当使用 MATCH_CONSTRAINT 时,控件仿佛一个橡皮泥,会被”弹簧“拉到无限远的地方,用刚才的 button 的例子说明,就是会被拉扯到父布局的大小。即 会充满建立约束的边缘。

ps:这里有个小坑,看完官方文档知道我去设置 MATCH_CONSTRAINT ,但是编译器却始终没有提示,直接输入也会报错,最后又重新去查看文档,发现直接设置 0dp 就等于 MATCH_CONSTRAINT ,巨汗。

Percent dimension

To use percent, you need to set the following:

  • The dimension should be set to MATCH_CONSTRAINT (0dp)

百分比尺寸便是基于 MATCH_CONSTRAINT 实现的,在此基础上还需要设置另外一个参数:

app:layout_constraintWidth_percent=".5"
app:layout_constraintHeight_percent=".5"

以上就是设置尺寸为 父布局 的百分之50,注意是父布局,该参数和 具体建立约束的控件 位置无关。

总结下:在设置 MATCH_CONSTRAINT 的前提下,默认尺寸为 充满当前约束 大小,在使用 layout_constraintWidth_percent layout_constraintHeight_percent 能直接设置该控件为 父布局 的百分比大小 与当前约束无关。

实战

以上就是通过 ConstraintLayout 实现百分比布局的全部主要内容,以下献上一个实例的完整代码以供参考:

android中的各种constrainlayout android constraintlayout百分比_机型适配_02

<?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:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--button在父布局 水平百分之30,竖直百分之20的位置-->
    <!--宽度为父布局宽度的百分之20,高度为父布局高度的百分之10-->
    <Button
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintVertical_bias="0.2"
        app:layout_constraintHeight_percent=".1"
        app:layout_constraintWidth_percent=".2"/>
</android.support.constraint.ConstraintLayout>