ConstraintLayout使用详解

转载文章:

约束布局ConstraintLayout看这一篇就够了

万字长文 - 史上最全ConstraintLayout(约束布局)使用详解

使用ConstraintLayout遇到的些许问题

1.ConstraintLayout介绍

约束布局ConstraintLayout 是一个ViewGroup,可以在Api9以上的Android系统使用它,它的出现主要是为了解决布局嵌套过多的问题,以灵活的方式定位和调整小部件。从 Android Studio 2.3 起,官方的模板默认使用 ConstraintLayout。

ConstraintLayout 官方文档

2.ConstraintLayout属性及使用

2.1 位置约束

2.1.1 基本方向约束

基本方向约束(部件对上下左右方向的约束),例如:

如图所示,TextView2在TextView1的右边,TextView3在TextView1的下面,这个时候在布局文件里面应该这样写:

<TextView
android:id="@+id/TextView1"
...
android:text="TextView1" />
<TextView
android:id="@+id/TextView2"
...
app:layout_constraintLeft_toRightOf="@+id/TextView1" />
<TextView
android:id="@+id/TextView3"
...
app:layout_constraintTop_toBottomOf="@+id/TextView1" />

上面代码中在TextView2里用到了app:layout_constraintLeft_toRightOf="@+id/TextView1"这个属性,他的意思是把TextView2的左边约束到TextView1的右边,如下图所示:

同理TextView3在TextView1的下面,就需要用到app:layout_constraintTop_toBottomOf="@+id/TextView1",即把TextView3的上面约束到TextView1的下面。

下面来看看相对定位的常用属性:

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_constraintStart_toEndOf

layout_constraintStart_toStartOf

layout_constraintEnd_toStartOf

layout_constraintEnd_toEndOf

2.1.2 文本基线对齐

layout_constraintBaseline_toBaselineOf比较特殊的约束,Baseline指的是文本基线,举个例子:

 如图所示,两个TextView的高度不一致,但是又希望他们文本对齐,这个时候就可以使用layout_constraintBaseline_toBaselineOf,代码如下:

<TextView
android:id="@+id/TextView1"
.../>
<TextView
android:id="@+id/TextView2"
...
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_constraintBaseline_toBaselineOf="@+id/TextView1"/>

效果如下:

 2.1.3 角度定位

角度定位指的是可以用一个角度和一个距离来约束两个空间的中心。举个例子:

<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintCircle="@+id/TextView1"
app:layout_constraintCircleAngle="120"
app:layout_constraintCircleRadius="150dp" />

上面例子中的TextView2用到了3个属性:

app:layout_constraintCircle="@+id/TextView1" 目标控件id

app:layout_constraintCircleAngle="120"(角度) 对于目标的角度(0-360)

app:layout_constraintCircleRadius="150dp"(距离) 到目标中心的距离

指的是TextView2的中心在TextView1的中心的120度,距离为150dp,效果如下:

 2.1.4 百分比偏移

有的时候我们需要让控件在父布局的水平方向或垂直方向的百分之多少的位置,可以使用如下属性:

app:layout_constraintHorizontal_bias="" 水平偏移 取值范围是0-1的小数

app:layout_constraintVertical_bias="" 垂直偏移 取值范围是0-1的小数

举个例子:

<TextView
android:id="@+id/TextView1"
...
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />

假如现在要实现水平偏移,给TextView1的layout_constraintHorizontal_bias赋一个范围为 0-1 的值,假如赋值为0,则TextView1在布局的最左侧,假如赋值为1,则TextView1在布局的最右侧,假如假如赋值为0.5,则水平居中,假如假如赋值为0.3,则更倾向于左侧。

2.1.5 居中

在RelativeLayout中,把控件放在布局中间的方法是把layout_centerInParent设为true,而在ConstraintLayout中的写法是:

app:layout_constraintBottom_toBottomOf="parent" 
app:layout_constraintLeft_toLeftOf="parent" 
app:layout_constraintRight_toRightOf="parent" 
app:layout_constraintTop_toTopOf="parent" 

意思是把控件的上下左右约束在布局的上下左右,这样就能把控件放在布局的中间了。

2.2 边距

2.2.1 外边距(margin)

ConstraintLayout的边距常用属性如下:

android:layout_marginStart

android:layout_marginEnd

android:layout_marginLeft

android:layout_marginTop

android:layout_marginRight

android:layout_marginBottom

<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>

TextView1的左边和上边约束到parent的左边和上边10dp,效果如下:

2.2.3 内边距(padding)

和外边距相似,只不过是相对于本身的边距,相当于在自己的外边加一片空白。

android:layout_margin

android:layout_marginStart

android:layout_marginLeft

android:layout_marginTop

android:layout_marginEnd

android:layout_marginRight

android:layout_marginBottom

2.2.3 goneMargin

goneMargin主要用于约束的控件可见性被设置为gone的时候使用的margin值,属性如下:

layout_goneMarginStart

layout_goneMarginEnd

layout_goneMarginLeft

layout_goneMarginTop

layout_goneMarginRight

layout_goneMarginBottom

举个例子:

假设TextView2的左边约束在TextView1的右边,并给TextView2设一个app:layout_goneMarginLeft="10dp",代码如下:

<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="@+id/TextView1"
.../>
<TextView
android:id="@+id/TextView2"
...
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_goneMarginLeft="10dp" />
</android.support.constraint.ConstraintLayout>

效果如下,TextView2在TextView1的右边,且没有边距。

这个时候把TextView1的可见性设为gone,效果如下:

TextView1消失后,TextView2有一个距离左边10dp的边距。

2.3 控件尺寸

2.3.1 尺寸限制

控件的尺寸可以通过3种不同方式指定:

  • 使用指定的尺寸
  • 使用wrap_content,让控件自己计算大小

当控件的高度或宽度为wrap_content时,可以使用下列属性来控制最大、最小的高度或宽度:

android:minWidth 最小的宽度

android:minHeight 最小的高度

android:maxWidth 最大的宽度

android:maxHeight 最大的高度

注意!当ConstraintLayout为1.1版本以下时,使用这些属性需要加上强制约束,如下所示:

app:constrainedWidth=”true”

app:constrainedHeight=”true”

  • 使用 0dp (MATCH_CONSTRAINT)

官方不推荐在ConstraintLayout中使用match_parent,可以设置 0dp (MATCH_CONSTRAINT) 配合约束代替match_parent,举个例子:

2.3.2 比例宽高(Ratio)

当宽或高至少有一个尺寸被设置为0dp时,可以通过属性layout_constraintDimensionRatio设置宽高比,举个例子:

<TextView
android:id="@+id/TextView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />

宽设置为0dp,宽高比设置为1:1,这个时候TextView1是一个正方形,效果如下:

除此之外,在设置宽高比的值的时候,还可以在前面加W或H,分别指定宽度或高度限制。 例如:

app:layout_constraintDimensionRatio="H,2:3"指的是 高:宽=2:3

app:layout_constraintDimensionRatio="W,2:3"指的是 宽:高=2:3

默认是宽:高

2.4 链

如果两个或以上控件通过下图的方式约束在一起,就可以认为是他们是一条链(图为横向的链,纵向同理)。

用代码表示:

<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" 
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/TextView2" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_constraintRight_toLeftOf="@+id/TextView3"
app:layout_constraintRight_toRightOf="parent" />
<TextView
android:id="@+id/TextView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/TextView2"
app:layout_constraintRight_toRightOf="parent" />

3个TextView相互约束,两端两个TextView分别与parent约束,成为一条链,效果如下:

一条链的第一个控件是这条链的链头,我们可以在链头中设置 layout_constraintHorizontal_chainStyle来改变整条链的样式。chains提供了3种样式,分别是:

CHAIN_SPREAD —— 展开元素 (默认);

CHAIN_SPREAD_INSIDE —— 展开元素,但链的两端贴近parent;

CHAIN_PACKED —— 链的元素将被打包在一起。

如图所示:

上面的例子创建了一个样式链,除了样式链外,还可以创建一个权重链。

可以留意到上面所用到的3个TextView宽度都为wrap_content,如果我们把宽度都设为0dp,这个时候可以在每个TextView中设置横向权重layout_constraintHorizontal_weight(constraintVertical为纵向)来创建一个权重链,如下所示:

<TextView
android:id="@+id/TextView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/TextView2"
app:layout_constraintHorizontal_weight="2" />
<TextView
android:id="@+id/TextView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_constraintRight_toLeftOf="@+id/TextView3"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="3" />
<TextView
android:id="@+id/TextView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/TextView2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="4" />

效果如下:

3.辅助工具

转载:

万字长文 - 史上最全ConstraintLayout(约束布局)使用详解

3.1 Guideline(参考线)

Guideline是一条参考线,可以帮助开发者进行辅助定位,并且实际上它并不会真正显示在布局中,像是数学几何中的辅助线一样,使用起来十分方便,经常被使用,Guideline也可以用来做一些百分比分割之类的需求,有着很好的屏幕适配效果,Guideline有水平和垂直方向之分,位置可以使用针对父级的百分比或者针对父级位置的固定距离

android:orientation="horizontal|vertical" 辅助线的对齐方式

app:layout_constraintGuide_percent="0-1" 距离父级宽度或高度的百分比(小数形式)

app:layout_constraintGuide_begin="" 距离父级起始位置的距离(左侧或顶部)

app:layout_constraintGuide_end="" 距离父级结束位置的距离(右侧或底部)

 <androidx.constraintlayout.widget.Guideline
        android:id="@+id/Guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.5" />
        
    <TextView
        android:id="@+id/A"
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:background="#FFFFFF"
        android:gravity="center"
        android:text="A"
        android:textColor="@color/black"
        android:textSize="25sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/Guideline" />

代码效果如下:

3.2 Barrier(屏障)

首先我们先看一个布局,布局有三个文本视图:左边的textView1和textView2;右边的textView3。textView3被限制在textView1的末尾,这工作得很好——它完全根据我们需要来定位和大小textView3。布局的效果如下:

但是如果textView2中的文本比textView1中的文本长(现实中经常出现),就会出现以下情况:

textView2被textView3覆盖,显然这不是我们想要的情况。如果我们在textView1和textView2的bottom后面设置一个barrier,然后把textView3约束到这个barrier后面,就解决了这个问题。

<TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:text="hshsf"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="8dp"
        android:text="hsahffdbfdbnd"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView1" />

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="end"
        app:constraint_referenced_ids="textView2,textView1" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:text="safbasbjfasllaksfn.s;djbgo;grw;ogu;ovfabjkv
jbnoeab';orgnabeobiourenb;oie;tbn;etobi;euobneotbnetobuoetbhetiav
boaejieiortbueotabuaoetb;rebhaoer;ugae;gaergieagure;ghr/ebogreobg
boerhbov;taeghvertgbejor;oguofgbrnoa'ubroeughforefgkrgfkkrsggsehj
sdhgayeribfgregfidudrghdraigrehgiirdgh;rdijerglirhgfkerifgbergfgb
sifgiergbrikgirgrghrgerf"
        app:layout_constraintLeft_toRightOf="@+id/barrier"
        app:layout_constraintTop_toTopOf="parent" />

效果图如下:

3.3 Group(组)

工作当中常常会有很多个控件同时隐藏或者显示的场景,传统做法要么是进行嵌套,对父布局进行隐藏或显示,要么就是一个一个设置,这显然都不是很好的办法,ConstraintLayout中的Group就是来解决这个问题的。Group的作用就是可以对一组控件同时隐藏或显示,没有其他的作用,它的属性如下:

app:constraint_referenced_ids="id,id" 加入组的控件id

例如:

上面效果图的代码如下:

<TextView
    android:id="@+id/textView1"
    android:layout_width="120dp"
    android:layout_height="60dp"
    android:layout_marginTop="56dp"
    android:gravity="center"
    android:text="textView1"
    android:textColor="@color/black"
    android:textSize="25sp"
    android:textStyle="bold"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.115"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/textView2"
    android:layout_width="120dp"
    android:layout_height="60dp"
    android:layout_marginTop="280dp"
    android:gravity="center"
    android:text="textView2"
    android:textColor="@color/black"
    android:textSize="25sp"
    android:textStyle="bold"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.758"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/textView3"
    android:layout_width="120dp"
    android:layout_height="60dp"
    android:layout_marginTop="164dp"
    android:gravity="center"
    android:text="textView3"
    android:textColor="@color/black"
    android:textSize="25sp"
    android:textStyle="bold"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.437"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<androidx.constraintlayout.widget.Group
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:visibility="visible"
    app:constraint_referenced_ids="textView1,textView2,textView3" />

如上述代码,textView1、textView2和textView3受Group控制,当Group的visiablity为visiable时,它们都是正常显示的,设置为gone时,它们都会隐藏。

3.4 Placeholder(占位符)

Placeholder的作用就是占位,它可以在布局中占好位置,通过app:content=""属性,或者动态调用setContent()设置内容,来让某个控件移动到此占位符中

示例代码如下:

<TextView
    android:id="@+id/textView"
    android:layout_width="100dp"
    android:layout_height="60dp"
    android:gravity="center"
    android:text="textView"
    android:textColor="@color/black"
    android:textSize="25sp"
    android:textStyle="bold"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<androidx.constraintlayout.widget.Placeholder
    android:layout_width="100dp"
    android:layout_height="60dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

代码效果图如下:

当我们设置android:id="@+id/textView"或者调用setContent()时,控件A就会被移动到Placeholder中,当然在布局中使用app:content=""显然就失去了它的作用。

3.5 Flow(流式虚拟布局)

2.6 Layer(层布局)

4.常见问题

转载:

使用ConstraintLayout遇到的些许问题

1、控件的宽、高都不可设置为 match_parent,否则所有的约束失效。ConstraintLayout里尽量不要出现match_parent,用“0dp”代替即可

2、欲使设置的margin生效,须指定控件的约束对象。例如,欲使marginTop生效,须设定layout_constraintTop_toTopOf

3、被Group持有的所有控件,其visiblity只能由Group决定

4、以当前布局中不能准确知道高度的View为标准,例如:在一个布局中,左边TextView的内容是固定的文字,右边TextView的内容须根据具体业务进行动态设置,则其高度是不确定的,这种情况下高度约束均以右边为中心

5、自定义组合控件使用ConstraintLayout作为布局的根时,使用LinearLayout作为自定义控件的父布局时会造成自定义封装的布局展示不正确(宽高变形,与测量方式有关)。推荐使用FrameLayout作为根布局,同时固定高度

6、欲使layout_constraintVertical_bias属性生效,须设置上下约束。同样欲使layout_constraintHorizontal_bias属性生效,须设置左右约束

7、若ConstraintLayout不是根布局,则其中的子控件的约束不能指定为 parent,但可指定为父控件ConstraintLayout的id

8、layout_marginLeft和layout_marginRight不起作用:控件左右都约束了parent,但有时左右margin不起作用,可能是因为layout_width设置成了match_parent或者wrap_content,须改为match_constraint(即0dp)才会起作用

9、Guideline:

(1)layout_constraintGuide_percent属性值可以为负值,有时某些特殊的需求会用到

(2)对Guideline设置相对位置属性是不生效的,因此当我们想要一个相对于某个view的Guideline时,约束布局是不能满足的。此时可以用一个不可见的View作为Guideline的替代品来实现一些特殊布局需求,如布局重叠,这种方式可以弥补margin不能设置为负值的不足

10、Chain:

(1)在chainStyle=spread时才可以使用加权layout_constraintHorizontal_weight和layout_constraintVertical_weight 。

(2)注意Chain中的控件互相引用id的格式,是“@+id/button1”而非”@id/button1”。

(3)可以用Chain实现控件居中

11、注意View.inflate(getActivity(), R.layout.item, null)和LayoutInflater.from(getActivity()).inflate(R.layout.item, parent, false)区别,有时二者对ConstraintLayout布局会有不同的影响

12、在ConstraintLayout中,控件除了可以设置layout_marginXXX外,还可以设置其依赖的控件gone之后的margin,即layout_goneMarginXXX。就是说,可以根据被依赖控件的visibility,设置两种margin

13.ConstraintLayout没有负数布局,但是我们可以利用Space达到相同的效果

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sourcetree是一个非常好用的git客户端,它提供了可视化的界面帮助开发者进行多人协作开发过程中的各种git操作,比如push、pull、add、commit、merge等等。 在使用Sourcetree之前,你需要先下载、安装和配置好环境。然后你可以打开Sourcetree,它会展示一个初始界面,其中包含了本地仓库的相关信息。 Sourcetree是一个强大的工具,但本文只介绍了一些常用的功能,并没有记录一些使用频率较低的功能。工具的目的是帮助我们提高工作效率,所以我们只需要掌握最有用的部分即可。 在正文部分,你可以了解到Sourcetree的各种功能,以及对应的git命令和如何使用这些功能。它详细介绍了各种常用操作,帮助你更好地使用Sourcetree进行版本控制。[1,2] 使用Sourcetree可以很方便地进行分支的检出和关联远程分支。当你使用命令行检出分支后,你还需要执行一些操作来与远程分支进行关联。但是Sourcetree非常友好,当你点击克隆按钮时,它会自动帮助你与远程仓库进行关联。 总之,Sourcetree是一个功能强大且易于使用的git客户端,它为开发者提供了可视化的界面来管理和执行各种git操作,帮助我们更高效地进行协同开发。[1,2,3]<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Sourcetree 使用详解](https://blog.csdn.net/weixin_43837354/article/details/105936140)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [SourceTree使用教程图文详解](https://blog.csdn.net/qq_41153943/article/details/120814918)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值