深入分析 ConstraintLayout 的原理及应用场景,万字总结
当然不是。
ConstraintLayout 的约束关系,使它具备了另一个特点,那就是可以添加引导线来辅助布局,所有布局都可以在界面上通过拖动完成。如图。
点击 layout 布局后,选择图示右上角的 Design 按钮,即可拖动控件。
而 RelativeLayout 并不具备这一特点,这也让 ConstraintLayout 的布局调整更为方便、快捷。
如果此时非 ConstraintLayout 布局,在上图左方,右键点击最上部分的父容器,选择 Convert XXX to Constraintlayout 即可转化为约束布局。
RelativeLayout、ConstraintLayout 都可以通过 LayoutParams 动态新建布局,即在代码中控制控件尺寸和位置,而不只是在 xml 文件中设置静态的布局。但是,ConstraintLayout 引入了一个新的类,即 ConstraintSet,使它可以实现动画效果,对控件的控制能力也更加强大,这是 RelativeLayout 不具备的能力。
性能上,ConstraintLayout 的渲染速度比 RelativeLayout 更快。
原因:
在布局上 RelativeLayout 内比 ConstraintLayout 多了一层 ViewGroup,如这样一种情况,屏幕分成两半,左半部分只有一个 button,右半部分从上到下有多个 button,左边的 button 需要居中对齐右边,那么便需要将右半部分的多个 button 用一个 viewgroup 包裹起来。这样便多了一层嵌套,渲染时间增加。
值得注意的是,LinearLayout 的渲染速度也快于 RelativeLayout,原因:因为 RelativeLayout 通过在水平、垂直方向对另一控件的依赖,来计算自身的位置,因此会执行两遍 measure,而 LinearLayout 只需测量一次。ConstraintLayout 是 RelativeLayout 的升级版,LinearLayout 的渲染速度同样快于 ConstraintLayout。
因此对于层次不深的简单布局,优先使用 LinearLayout。
这里可能会有人有疑惑,那层次深与不深又怎么划分呢?三层、四层算深还是五层、六层?
个人的想法是,如果布局仅有一层,不需嵌套,直接使用 LinearLayout;如果嵌套多于一层,而根布局需要采用 RelativeLayout 或 ConstraintLayout 时,可以直接采用 ConstraintLayout。
ConstraintLayout 使用条件与场景
使用条件
ConstraintLayout 布局内的控件必须有水平方向和垂直方向的约束,来表示与父布、兄弟控件的连接或对齐。
水平方向上,start 和 end 为一组。
垂直方向上,top 和 bottom 为一组。
约束如下。
//与父布局底部对齐(parent 可改为其他控件 ID,即与其他控件底部对齐,下同)app:layout_constraintBottom_toBottomOf="parent"
//与父布局顶部对齐 app:layout_constraintTop_toTopOf="parent"
//与父布局左端对齐 app:layout_constraintStart_toStartOf="parent"
//与父布局右端对齐 app:layout_constraintEnd_toEndOf="parent"
//在父布局的上方(看属性最右边的元素,即 Top,下同)app:layout_constraintBottom_toTopOf="parent"
//在父布局的下方 app:layout_constraintTop_toBottomOf="parent"
//在父布局的右方 app:layout_constraintStart_toEndOf="parent"
//在父布局的左方 app:layout_constraintEnd_toStartOf="parent"
使用前导包
在顶级 build.gradle 文件中
repositories {google()}
模块级 build.gradle
// 尽可能地下载最新版本,如果不确定最新版本号,可以先写入 1.0.0,系统会标注提醒最新版本号.dependencies {implementation "androidx.constraintlayout:constraintlayout:2.0.4"}
使用场景
场景 a:A 控件与“222”控件居中对齐,且“222”控件在 A 控件下方。如图(即基于某控件的一边,居中对齐)
代码实现如下:
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.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">
<TextViewandroid:id="@+id/tv1"android:layout_width="100dp"android:layout_height="40dp"android:gravity="center"android:text="A"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" />
//因为要位于下方,所以使用 layout_constraintTop_toBottomOf 属性;//同时左右两边要基于另一控件对齐(因为要居中)<TextViewandroid:id="@+id/tv2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center"android:text="222"app:layout_constraintStart_toStartOf="@id/tv1"app:layout_constraintEnd_toEndOf="@id/tv1"app:layout_constraintTop_toBottomOf="@id/tv1"/>
</androidx.constraintlayout.widget.ConstraintLayout>
居中用法引申:同一维度(上下或左右)的两个方向同时出现,且相对于父布局对齐。
非居中用法引申:若不居中对齐,而是基于某一边对齐,只需去掉同一个维度的某一个方向。例如,上方代码中,去掉 app:layout_constraintEnd_toEndOf="@id/tv1", 即实现 A 与“222”控件左方对齐,且 A 在“222”控件上方。
场景 2:六个控件在布局中以三行三列形式分布,且行均分布局高度,列均分布局宽度。如图。
核心实现流程如下:
每一个相对的控件,都要写出相约束的属性(比如 layout_constraintEnd_toStartOf;layout_constraintStart_toEndOf)。
每个控件四个方向的约束位置都要写出来。
每一个横向或竖向位置的两端,必须与 parent 相对。
// 横向:app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent";
// 竖向:app:layout_constraintTop_toTopOf="parent";app:layout_constraintBottom_toBottomOf="parent";
利用权重实现均分(weight 属性)
均分时,长或宽都必须为 0。
代码如下所示。
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.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:cont
ext=".MainActivity">
/*核心代码*/<Buttonandroid:id="@+id/btn1"android:layout_width="0dp"android:layout_height="0dp"android:text="btn1"app:layout_constraintBottom_toTopOf="@id/btn4"app:layout_constraintEnd_toStartOf="@+id/btn2"app:layout_constraintHorizontal_weight="1"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_weight="1" />
<Buttonandroid:id="@+id/btn2"android:layout_width="0dp"android:layout_height="0dp"android:text="btn2"app:layout_constraintBottom_toTopOf="@id/btn5"app:layout_constraintEnd_toEndOf="@id/btn3"app:layout_constraintHorizontal_weight="1"app:layout_constraintStart_toEndOf="@+id/btn1"app:layout_constraintTop_toTopOf="@+id/btn1"app:layout_constraintVertical_weight="1" />
<Buttonandroid:id="@+id/btn3"android:layout_width="0dp"android:layout_height="0dp"android:text="btn3"app:layout_constraintBottom_toTopOf="@id/btn6"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_weight="1"app:layout_constraintStart_toEndOf="@+id/btn2"app:layout_constraintTop_toTopOf="@+id/btn2"app:layout_constraintVertical_weight="1" />
评论