一、前言:
因为在复杂布局,我们会一直用RelativeLayout和LinearLayout去嵌套,因为嵌套的ViewGroup会导致手机多次测量和绘制,从而影响性能,如果嵌套严重可能出现掉帧或卡顿。
使用ConstraintLayout一招入魂。一句话概括是:传统布局能实现的,它能轻松实现实现。传统布局不能实现的,它也能实现。
二、使用:
1、使用1
如图下图所示,我们分别用RelativeLayout和ConstraintLayout去实现它:
![](https://img.haomeiwen.com/i11268516/80f5cc860453381d.png)
在xml里。我们无法用RelativeLayout去实现,如下分析
- B在A下方,通过 android:layout_below="@+id/txt_a"实现
- B要在A底部边框上,垂直居中。那么我们要知道B的height。B再使用marginTop="-height/2"才能达到效果。所以在xml里无法实现,只能去代码里动态计算。
使用ConstraintLayout则可轻松完成:
<androidx.constraintlayout.widget.ConstraintLayout ...>
<TextView
android:id="@+id/txt_a"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
.../>
<TextView
app:layout_constraintRight_toRightOf="@+id/txt_a"
app:layout_constraintLeft_toLeftOf="@+id/txt_a"
app:layout_constraintTop_toBottomOf="@+id/txt_a"
app:layout_constraintBottom_toBottomOf="@+id/txt_a"
android:id="@+id/txt_b"
.../>
</androidx.constraintlayout.widget.ConstraintLayout>
2、如图:靠右边
![](https://img.haomeiwen.com/i11268516/73cd10508ce83e35.png)
实现如图功能:
<TextView
...
app:layout_constraintRight_toRightOf="parent"
/>
layout_constraintRight_toRightOf 属性还有left、right、top、bottom、start、end等搭配使用。什么意思呢?
- 第一个Right代表 本控件的右边
- 第二个Right代表 要位于目标控件右边。
- 所以app:layout_constraintRight_toRightOf=“parent”; 红色A的右边位于父容器的右边
注意start、end是因为很多国家阅读习惯不一样,比如我们是习惯从左往右阅读。所以start对于我们来说就是left,end就是right。
3、如图:居中
![](https://img.haomeiwen.com/i11268516/09952ee9fba7f8df.png)
实现如图功能:
<TextView
...
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
/>
右边和父控件右边对齐,左边和父控件左边对齐。这样就可以达到横向居中,同理竖直。
注意这里居中了。同样还可以用margin进行偏移。也可以利用属性app:layout_constraintHorizontal_bias=“0.5”,进行横向偏移,0.5意思也还算居中。同理竖直的属性。
4、如图:充满屏幕
![](https://img.haomeiwen.com/i11268516/eae32bcf31e743c0.png)
比如B要在A的右边,且相对A上下居中,而且B要充满剩余横屏:
<TextView
app:layout_constraintLeft_toRightOf="@+id/txt_a"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/txt_a"
app:layout_constraintBottom_toBottomOf="@id/txt_a"
android:layout_width="0dp"
...
/>
要想充满全屏把宽度设置为0dp。然后通过以下代码:
- app:layout_constraintLeft_toRightOf="@+id/txt_a";B的左边和A的右边对齐
- app:layout_constraintRight_toRightOf=“parent”;B的右边和父容器的右边对齐
这样B就在A的右边,且横向充满屏。注意:在约束布局里match_parent是不生效的。
要想B竖直方向与A平行的话,通过如下代码:
- app:layout_constraintTop_toTopOf="@+id/txt_a";B的上边和A的上边对齐
- app:layout_constraintBottom_toBottomOf="@id/txt_a";B的下边和A的下边对齐
这样就可以让B在A右边,上下居中。
5、如图:不嵌套居中
![](https://img.haomeiwen.com/i11268516/6f79b9d8cd3fa63b.png)
在列表里我们经常会遇到这样的需求,A是一张图片,title是标题,des是描述。用RelativeLayout的做法是:继续用一个layout布局包裹title和des,居中然后放在A的右边。
用ConstraintLayout的话不用嵌套,3个view就搞定了。如下:
<ImageView
...
/>
<TextView
app:layout_constraintTop_toTopOf="@+id/image"
app:layout_constraintBottom_toTopOf="@+id/txt_des"
android:id="@+id/txt_title"
...
/>
<TextView
app:layout_constraintTop_toBottomOf="@+id/txt_title"
app:layout_constraintBottom_toBottomOf="@+id/image"
* 这个时候你会发现还没有居中因为还缺了一条约束,title在des上边;
android:id="@+id/txt_des"
...
/>
为例3,已经讲过如何全屏了,这里主要讲title和des如何居中:
- des 在title下面;app:layout_constraintTop_toBottomOf="@+id/txt_title"
- title上边和图片A上边对齐;app:layout_constraintTop_toTopOf="@+id/image"
- des下边和图片A下边对齐;app:layout_constraintBottom_toBottomOf="@+id/image"
- 这个时候你会发现还没有居中因为还缺了一条约束,title在des上边; app:layout_constraintBottom_toTopOf="@+id/txt_des",这和RelativeLayout有些区别
这里还有一个属性文本基线对齐,和RelativeLayout里的 layout_alignBaseline 是一样的效果
- app:layout_constraintBaseline_toBaselineOf="@+id/txt_a"
6、角度定位
![](https://img.haomeiwen.com/i11268516/18bd65380052ca46.png)
实现代码如下:
<TextView
android:id="@+id/txt_a"
...
/>
<TextView
app:layout_constraintCircle="@+id/txt_a";
app:layout_constraintCircleAngle="90"
app:layout_constraintCircleRadius="100dp"
android:id="@+id/txt_b"
...
/>
- app:layout_constraintCircle="@+id/txt_a";B相对于A角度定位
- app:layout_constraintCircleAngle=“90”;角度定位角度为90°
- app:layout_constraintCircleRadius=“100dp”;B中心与A中心相差100dp
7、边距
margin 值要生效,一定是伴随约束属性的。什么意思呢,要实现如图功能:
![](https://img.haomeiwen.com/i11268516/c12410f94a320bb6.png)
代码实现如下:
<TextView
android:id="@+id/txt_a"
...
/>
<TextView
android:layout_marginLeft="20dp"
app:layout_constraintLeft_toRightOf="@+id/txt_a"
android:id="@+id/txt_b"
...
/>
- 比如B左边和A的右边对齐app:layout_constraintLeft_toRightOf="@+id/txt_a",此时在B上加上margin值生效
- 如果这个时候在A上加上android:layout_marginRight=“50dp”,是不生效的。谨记
8、goneMargin
图1如下:
![](https://img.haomeiwen.com/i11268516/ae380c3c612b88d8.png)
图2如下:
![](https://img.haomeiwen.com/i11268516/a1f6ed0f6eeceb37.png)
解释:
1、显示A控件的时候,执行 android:layout_marginTop="50dp";
2、隐藏A控件的时候,执行 app:layout_goneMarginTop="10dp";
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/txt_a"
android:layout_width="@dimen/ui_dp100"
android:layout_height="@dimen/ui_dp100"
android:visibility="visible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="#f00"
android:text="A"
android:gravity="center"
android:textColor="#fff"
android:textSize="20sp"
/>
//意思就是当有约束的控件隐藏时,goneMargin就会生效,那么B就会距离顶部10dp。
<TextView
android:id="@+id/txt_b"
android:layout_width="@dimen/ui_dp100"
android:layout_height="@dimen/ui_dp100"
app:layout_constraintTop_toBottomOf="@+id/txt_a"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_goneMarginTop="10dp"
android:layout_marginTop="50dp"
android:background="#0f0"
android:text="B"
android:gravity="center"
android:textColor="#fff"
android:textSize="20sp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
9、尺寸
在ConstraintLayout里,设置尺寸大小的有3个:
- 设置固定的dp值
- wrap_content
- 0dp(MATCH_CONSTRAINT),前面讲过match_parent是不生效的。如果想达到match_parent的效果只能通过0dp和约束来达到。
10、layout_constraintWidth_max
- 属性 layout_constraintWidth_max 在使用dp固定值的时候和 android:maxWidth=“100dp” 用法是一致的。
- 但是layout_constraintWidth_max可以搭配属性 app:layout_constraintWidth_percent=“0.5” 使用,什么意思呢。
比如我们要实现红色区域占父容器宽度的一半
![](https://img.haomeiwen.com/i11268516/1e74ca92319eaa9d.png)
实现代码如下:
<TextView
app:layout_constraintLeft_toLeftOf="parent"
android:layout_width="0dp"
android:text=""
app:layout_constraintWidth_max="wrap"
app:layout_constraintWidth_percent="0.5"
...
/>
这里这样设置的时候,意思最大宽度是父容器的一半。注意这里text=""空的时候,会像图中直接展示父容器的一半,假设我们给text="A"设置上值后,如下图,那么只会展示A的宽度,但最大宽度是父容器一半。
![](https://img.haomeiwen.com/i11268516/fdaf42720ce41edd.png)
11、app:layout_constrainedWidth
app:layout_constrainedWidth=“true” 属性,是按约束去限制宽度,什么意思呢?我们先不加上这条属性,实现如下图效果是这样的:
![](https://img.haomeiwen.com/i11268516/ab90a50fd67c3152.png)
代码是这样的:
<TextView
android:id="@+id/txt_a"
...
/>
<TextView
app:layout_constraintLeft_toLeftOf="@id/txt_a"
app:layout_constraintRight_toRightOf="@id/txt_a"
app:layout_constraintTop_toBottomOf="@+id/txt_a"
android:id="@+id/txt_b"
android:layout_width="wrap_content"
android:text="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
...
/>
给txt_b加上 app:layout_constrainedWidth=“true” 属性后,就会实现下面的效果:
![](https://img.haomeiwen.com/i11268516/7678d0d86bc88be6.png)
意思就是B的最大宽度按照A的宽度来约束,这里要注意的是,B的宽度是wrap_content。假设这里是0dp的话,那这里就另外一种情况了,意思就是B的宽度和A的宽度一样宽。
12、设置宽高比(Set size as a ratio)
<ImageView
android:id="@+id/imageView2"
android:layout_width="200dp"
android:layout_height="0dp"
android:layout_marginTop="156dp"
android:scaleType="fitXY"
android:src="@drawable/ic_launcher_background"
app:layout_constraintDimensionRatio="h,16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
![](https://img.haomeiwen.com/i11268516/d33ba84465371888.png)
① 宽固定时使用(h,16:9),高固定时使用(w,16:9),代表宽高比;
② 使用dimensionRatio一个边要设置为match_constraint,一个边是固定大小
13、Barrier
![](https://img.haomeiwen.com/i11268516/85624c57b018a253.png)
假设有3个控件A、B、C,如果我们A,B的宽度不固定,同时又希望C在A,B的右边。如果用一个布局把A,B包裹起来,然后让C在A,B右边可以实现,如果不像嵌套就要通过Barrier了,如下图
![](https://img.haomeiwen.com/i11268516/4f886d4414a1466b.png)
实现代码如下:
<TextView
android:id="@+id/txt_1"
...
/>
<TextView
android:id="@+id/txt_2"
app:layout_constraintTop_toBottomOf="@+id/txt_1"
...
/>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="right"
app:constraint_referenced_ids="txt_1,txt_2" />
<TextView
android:id="@+id/txt_3"
app:layout_constraintLeft_toRightOf="@+id/barrier"
...
/>
Barrier属性有:
- app:barrierDirection=“right” 为屏障时,哪个方向的屏障,图中是A和B的右边
- app:constraint_referenced_ids=“txt_1,txt_2” 为屏障引用的id,用逗号隔开
网友评论