在学习控件的使用之前,了解下布局的相关知识是十分必要的。今天就来看看ConstraintLayout布局。
ConstraintLayout是Android Studio 2.2中主要的新增功能之一,ConstraintLayout是使用可视化的方式来编写界面。它的出现主要是为了解决布局嵌套过多的问题,以灵活的方式定位和调整小部件。
约束布局ConstraintLayout 是一个ViewGroup,可以在Api9以上的Android系统使用。ConstraintLayout是采用约束的方式来指定各个控件的位置和关系的。
关键听说阿里都让使用这玩意。。。。。。
在项目中使用ConstraintLayout
首先,我们的确认在我们项目的build.gradle文件中是否添加了google存储仓库,对于使用高一点版本的Android Studio来说这一点不需要担心。。
下一步在我们app的build.gradle文件中添加ConstraintLayout依赖,这一步新一点的版本我们也不需要去手动添加。。。不放心的可以确认下。
现在ConstraintLayout在我们创建布局文件的时候已经是默认的布局了。可想这些事我们都不需要操心了。
如果上面两个你检查完了,发现得自己添加的话,那么再多做一件事情吧。
点解"Sync Project with Gradle Files"进行一下同步吧.
好了,新建一个空的Activity,并勾选生成布局文件选项,看看出来的布局文件:
编写布局可以拖也可以写,这里选择手写xml布局文件。习惯了还是觉得写的来的快,勿喷。。。
使用相对定位(Relative positioning)
相对定位是我们在ConstraintLayout布局中很基础的一种使用姿势了,使用相对定位允许我们将给定的控件相对于另一个控件进行定位。常见的使用姿势是:控件给定一侧限制为任何其他控件的另一侧。
看个示意图:
那么该如何设置呢?
语法格式示例: app:layout_constraintLeft_toRightOf="控件id"
如果目标控件为父控件则id可以直接写成parent,否则写控件的id。
在上面的布局文件中添加一个Button,不做任何布局约束。
可用的约束:
layout_constraintLeft_toLeftOf
: 当前控件的Left在目标控件的Left上
layout_constraintLeft_toRightOf
: 当前控件的Left在目标控件的Right上
layout_constraintRight_toLeftOf
: 当前控件的Right在目标控件的Left上
layout_constraintRight_toRightOf
: 当前控件的Right在目标控件的Right上
layout_constraintTop_toTopOf
: 当前控件的Top在目标控件的Top上
layout_constraintTop_toBottomOf
: 当前控件的Top在目标控件的Bottom上
layout_constraintBottom_toTopOf
: 当前控件的Bottom在目标控件的Top上
layout_constraintBottom_toBottomOf
: 当前控件的Bottom在目标控件的Bottom上
layout_constraintBaseline_toBaselineOf
:当前控件的Baseline在目标控件的Baseline上
layout_constraintStart_toEndOf
: 当前控件的Start在目标控件的End上
layout_constraintStart_toStartOf
: 当前控件的Star在目标控件的Star上
layout_constraintEnd_toStartOf
: 当前控件的End在目标控件的Start上
layout_constraintEnd_toEndOf
: 当前控件的End在目标控件的End上
上下左右就不多说了,都明白啥意思,start和end这里给张示意图大家脑部一下:
首先我们添加一个Button,让其位于屏幕中央位置:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="屏幕居中">
</Button>
当然我们也可以使用left,right来实现水平居方向的约束:
`
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="屏幕居中">
</Button>
在添加两个Button:
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn1"
app:layout_constraintBottom_toTopOf="@+id/btn1"
android:text="按钮2">
</Button>
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toLeftOf="@+id/btn1"
app:layout_constraintTop_toBottomOf="@+id/btn1"
android:text="按钮3">
</Button>
使用Margins
可用列表:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
我们修改下布局文件:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="50dp"
android:layout_marginRight="50dp"
android:layout_marginBottom="100dp"
android:text="按钮1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
注意:margin属性需要配合约束来设置,比如你设置了左边的约束,那么你就可以使用android:layout_marginStart和android:layout_marginLeft,否则不会生效。
看个例子:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="50dp"
android:text="按钮1"
app:layout_constraintEnd_toStartOf="@+id/btn2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
></Button>
<Button
android:id="@+id/btn2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:layout_marginRight="20dp"
android:text="按钮2"
app:layout_constraintStart_toEndOf="@+id/btn1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
运行结果:
这里去掉右边和btn2的约束,大家再看下效果:
//app:layout_constraintEnd_toStartOf="@+id/btn2"
总之就是一句话,控件和谁有约束,在哪个方向的约束那么就可以在哪个方向设置Margin。
这里还有一种情况,那就是我们添加约束的目标控件在某些场合需要隐藏(即设置属性为GONE)的时候,我们可指定控件相对于其他控件的边距。此时需要使用下面的属性:
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
看个例子:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮2"
app:layout_constraintStart_toEndOf="@+id/btn1"
app:layout_constraintTop_toTopOf="parent"
app:layout_goneMarginLeft="20dp"></Button>
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮3"
app:layout_constraintStart_toEndOf="@id/btn2"
app:layout_constraintTop_toTopOf="parent"></Button>
这里摆放了三个在一行的按钮:
将按钮1的visibility设置为gone
android:visibility="gone"
此时按钮2左边的约束就相对于是parent了,那么此时按钮2应该距离左边20dp:
当然了,实际的使用比这复杂的多, 这里只希望通过这样的例子能大概明白是怎么用的,到了实际使用的时候能够快速入手。
Bias
首先我们看个例子:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
有如上设置的button,那么这个button到底是怎么在屏幕显示的呢?
我刚开始以为是这个样子的:
我们想一下start与parent左侧对其,end与parent右侧对其,那不是相当于设置为match_parent吗?可实际上我们给按钮的宽度设定是wrap_content,也就是说button是没有办法向两边撑开的。显然这个猜测是不正确的。
那么如果我们把layout_width设为0dp,是不是就能 达到这样的效果呢?验证之后发现果然是的。
官方文档的解释是:当给控件在水平方向添加相反的约束(当然了是针对同一个target)时,constraintlayout布局会将控件显示在target宽度的中间。就像两个相反的力一样,使控件两边的空白相同。
对于上面的例子来说,就是将按钮1居中显示:
遇到上面的情况,我们可能希望按钮靠左边显示,此时我们就需要借助Bias属性来进行控制。
可选值:
layout_constraintHorizontal_bias
//水平方向偏移
layout_constraintVertical_bias// 垂直方向偏移
这两个值得取值范围时:0 ~ 1,默认为0.5,即居中。不在这个范围的话,在屏幕中无法显示出来。
为按钮1添加水平方向的偏移,方向时从左到右。
app:layout_constraintHorizontal_bias="0"
将值设置为0,意味着我们的控件将在水平方向的左边开始位置开始显示。
那么设置为1的时候,自然就在最右边了。
设置为0.3:
垂直方向就不再演示了,效果一样的。
Circular positioning
这个该怎么翻译呢,直译的话就是圆形定位。官方给出的解释大概意思是这样的;
我们可以相对于一个控件的中心位置,以一定的角度和半径来约束目标控件的中心位置。
所以我还是将之称呼为圆心定位算了,不喜勿怪,英语水平有限。。。
看张示意图:
简单来说就是使用圆心定位进行约束,那么目标控件的中心点一定在以该控件中心,半径为n的圆角度为m的位置处。
可用属性:
layout_constraintCircle :
目标控件id
layout_constraintCircleRadius :圆半径
layout_constraintCircleAngle :角度 (取值: 0 ~ 360)
看个实例:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮1"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleAngle="90"
app:layout_constraintCircleRadius="100dp" />
这里我们指定半径为100dp,然后角度为90度,也就是和按钮1的中心点平齐。
Dimensions constraints
尺寸约束,这里针对的是对ConstraintLayout布局本身,注意:这些最小和最大尺寸将在ConstraintLayout的尺寸设置为WRAP_CONTENT时使用。
可用参数;
android:minWidth
android:minHeight
android:maxWidth
android:maxHeight
看个例子:
<?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"
android:background="@color/colorPrimaryDark"
tools:context=".QConstraintLayout">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:minWidth="200dp"
android:minHeight="100dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorPrimaryDark"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
实际上这些属性在将尺寸设置为match_parent的时候同样可用,不过存在布局显示差异,有兴趣的朋友可以试试。
Widgets dimension constraints:控件尺寸约束
我们可通过以下3种不同方式设置android:layout_width和android:layout_height属性值指定控件的尺寸。
使用指定数值
使用wrap_content
使用0dp,相当于match_constraint
不建议对ConstraintLayout中包含的控件使用MATCH_PARENT。
如果我们在指定 wrap_content属性的情况下,还想对控件进行特别的约束,那么可以使用下面的属性进行设置:
app:layout_constrainedWidth=”true|false”
app:layout_constrainedHeight=”true|false”
这里在说一下当设置layout_width或者layout_height为0dp的时候,默认行为是使结果大小占用所有可用空间。注意只有两边都存在约束的时候才能看到效果哦。
示例:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
android:text="测试1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:text="测试22"
app:layout_constraintStart_toEndOf="@+id/btn1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
运行效果:
如果我们去掉右边的约束:
app:layout_constraintEnd_toEndOf="parent"
看到这里大家应该清楚该怎么用了吧。。。要想有效果至少我的有一个宽度和高度让我去适应吧。。
Ratio
简单点就是百分比布局。
使用前提是:ayout_width或者layout_height至少有一个设置为0dp。
属性:
layout_constraintDimensionRatio
可选值:
浮点值,表示宽度和高度之间的比率
“宽度:高度”形式的比率,添加H约束高度,添加W约束宽度。
示例:
<Button
android:id="@+id/btn1"
android:layout_width="150dp"
android:layout_height="0dp"
android:background="@color/colorPrimaryDark"
android:text="测试1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,1:3"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn2"
android:layout_width="150dp"
android:layout_height="0dp"
android:background="@color/colorAccent"
android:text="测试22"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="W,1:3"
app:layout_constraintTop_toTopOf="@+id/btn1" />
效果图:
Chains
在横轴或或者竖轴上的控件相互约束时,可以组成一个链式约束。链在单个轴(水平或垂直)上提供类似行的行为。另一个轴可以独立约束。
如果一组控件通过双向连接链接在一起,则它们被视为链。链由链的第一个元素(链的“头部”)上设置的属性控制.链头是水平链的最左侧控件,垂直链的最顶部控件。
可用属性:
app:layout_constraintHorizontal_chainStyle
app:layout_constraintVertical_chainStyle
可选值:
spread模式:元素将展开(默认样式);
spread_inside模式: 类似spread模式,但链的端点不会分散;
含有权重spread模式:如果设置了某个或某些控件MATCH_CONSTRAINT(0dp),这个或这些控件将分割可用空间;
packed模式:链条的元素将被包装在一起。然后,子项的水平或垂直偏差属性将影响打包元素的定位;
下图是各种取值的表现形式。
具体示例就贴出来了。