ConstraintLayout的诞生,是为了解决我们在平常开发中的复杂多层级布局的问题,在一定程度上进行布局的优化。它有些类似RelativeLayout的功能,都是通过View质之间的相对位置或者View相对于父布局的位置来控制的。但是ConstraintLayout比Relative更加的灵活,方便。而且Android studio提供了ConstaintLayout的可视化编辑工具,可以直接进行拖拽来设置XML的布局。并且在API 2.3(Level 9)以上都可以使用ConstraintLayout。
现在Android studio3.0以上的只要新建Activity的时候生成的默认的xml文件外层布局应该都是ConstraintLayout。如果不是,也没关系,可以使用下面的方法在项目中添加依赖。
1.在对应的project的gradle文件中添加谷歌的仓库依赖maven.google.com
repositories {
google()
}
2.在对应module下的build.gradle文件中添加下面的依赖(版本可以不同)。
dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
}
重新build之后就可以使用ConstraintLayout了。
上面添加依赖成功之后,就可以开始创建我们的布局了。创建布局有两种方式:
1.对原本存在的布局进行修改,如下图所示选择Design,在Component Tree中跟布局点击右键,选择Convert xxx to ContraintLayout。
2.直接创建新的XML文件,直接在Root Tag 上填写 android.support.constraint.ConstraintLayout 就可以创建以ConstraintLayout为跟布局的XML文件了。
对于ConstraintLayout的使用,我其实更喜欢用我们平时喜欢操作XML文件的方式去控制,我觉得这样控制的更加精准,拖拽的方式我这种粗人有的时候一个像素不好调整,当然也可以XML代码操作和拖拽操作相结合的方式。如果大家想学习拖拽的方式来操作ConstraintLayout的话可以看看这篇文章,里面关于拖拽摆放XML写的相当到位清楚了。我这里还是写一些关于XML布局代码相关的操作。
上面是一段很简单的代码。放置了一张背景图片还有两个textView 实现的效果就是两个textView居中显示。
在我们平时写的代码中,要想实现这一效果,其实就是相当于将两个TextView放在一起,放入一个LinearLayout或者RelativeLayout中,然后让LinearLayout或者RelativeLayout居中显示,就可以达到两个TextView的组合都居中显示。但是使用ConstraintLayout之后,就可以不需要这外面的一层布局容器就可以达到这个实现效果。这样就减少了布局的层级了。这里先不细讲,先看看我们上面各种app:layout_****的相关属性了,这些属性后面接的都是已经存在的控件的id或者parent。例如上面的 app:layout_constraintLeft_toLeftOf="@id/photo",下面的解释都以后面的值为"@id/photo"为例子的
layout_constraintLeft_toLeftOf //控件的左边 与photo的左边对其
layout_constraintLeft_toRightOf //控件的左边 处于id为photo的右边,也就是控件位于photo的右边
layout_constraintRight_toLeftOf //控件的位于photo控件的左边
layout_constraintRight_toRightOf //控件的右边与id为photo的控件的右边对其
layout_constraintTop_toTopOf //控件的顶部与id为photo的控件的顶部对其
layout_constraintTop_toBottomOf //控件位于id为photo的控件的下边
layout_constraintBottom_toTopOf //控件位于id为photo的控件的上边
layout_constraintBottom_toBottomOf //控件的底部与id为photo的控件的底部对其
layout_constraintBaseline_toBaselineOf //控件的基准线与 id为photo的控件的基准线对其
layout_constraintStart_toEndOf //和 layout_constraintLeft_toRightOf 类似
layout_constraintStart_toStartOf //和layout_constraintLeft_toLeftOf 类似
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf
其实看上面的解释可以发现一个简单的规律,例如layout_constraintLeft_toLeftOf 这个属性,前面的constraintLeft后面是toLeftOf,这两个值都是left,说明设置的是左边与某个控件的左边对其,也就是只要前后都是设置的left ,right,top,bottom同一个方向值得话,就表示与后面的某个控件的某个方向对其,后面的start,end,baseline都是一个意思。上面的属性都是多个配合使用才能唯一确定位置的。上面的属性只能控制上下左右 开始或者end的位置要具体还可以借助以下几个属性控制精确的位置。
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
和我们平时自己写的类似的margin值意义相同。还有介个比较好玩的属性值
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
当你所依赖的View的为View.GONE的时候,这些你设置的对应的属性值就会起作用了例如下面的例子:
上面设置id为button2的Button的左边界处于id为button1的右边,也就是button2在button1的右边,还设置了app:layout_goneMarginLeft="20dp"这个属性,也就是当button1为View.GONE的时候,button2的这个属性值会生效,也就是margintLeft=20dp会生效,当button1为View.VISIBLE或者为View.INVISIBLE的时候这个属性值都会生效。很神奇有木有。其他的属性值同解。
和普通的View差不多,在ConstraintLayout容器中的View,它们宽高也有三个可选值:
1.固定尺寸值:就像我们写的20dp,100dp一样,可以给View设置一个固定的宽高值。
2.wrap_content:包裹内容,就是让android系统根据自身的情况去计算View的大小。
3.match_constraint:和我们原来的match_parent有点类似,但是一般不建议使用。直接使用width = "0dp"或者height="0dp"加上left/top/right/bottom属性值为parent可以实现match_constraint的类似match_parent效果。
Ratio字面意思就是比率,这也是ConstraintLayout区别传统布局容器中一个很好用的属性。
例如上面的代码中设置宽度为wrap_content,而app:layout_constraintDimensionRatio="1:1"的设置为1:1,默认情况下,这个属性的值可以写为app:layout_constraintDimensionRatio="0.5" 或者上面的1:1 或者H,1:1 亦或者 W,1:1。下面讲解这个几个数值的意思
app:layout_constraintDimensionRatio="0.5" 也就是控件的宽高比为0.5也就是 w/h = 0.5 高是宽的2倍。
app:layout_constraintDimensionRatio="1:1" 控件的宽高比为1:1,也就是宽和高相等。
app:layout_constraintDimensionRatio="H,3:1" 标识控件的宽高比为3:1也即是 W:H = 3:1
app:layout_constraintDimensionRatio="W,3:1" 标识控件的宽高比为1:3也即是 W:H = 1:3
上面的代码 拷贝到Android studio的xml文件中你会返现宽高比不是1:1,是因为什么原因呢?是因为没有设置位置属性,加上位置相关的属性就可以显示宽高比为1:1了
链条在同一个轴上(水平或者垂直)提供一个类似群组的统一表现。另一个轴可以单独控制。
如果一组小部件通过双向连接(见图,显示最小的链,带有两个小部件),则将其视为链条。
链条由在链的第一个元素(链的“头”)上设置的属性控制:头是水平链最左边的View,或垂直链最顶端的View。
先看下面这段代码 和效果就能明白margin的意思了
左边的图片是设置了android:layout_marginLeft="100dp"的效果 右边是去掉这个属性的效果,当我们设置了chains并且制定了某个控件的margin,就相当于整个链条都有了margin值。让后再去根据下面的属性去设置相关的位置。
当在链的第一个元素上设置属性 layout_constraintHorizontal_chainStyle
或layout_constraintVertical_chainStyle
时,链的行为将根据指定的样式(默认为CHAIN_SPREAD
)而更改。style可以取以下几个值:
spread
- 元素将被展开(默认样式)spread_inside
- 和spread类似,但链的端点将不会扩展为MATCH_CONSTRAINT
,则它们将拆分可用空间packed
- 链的元素将被打包在一起。 孩子的水平或垂直偏差属性将影响包装元素的定位我们可以角度和距离 来约束一个控件与另外一个控件的位置关系,可以用下面几个属性控制对应的位置关系:
layout_constraintCircle
: 后面接控件的id,就是我们以某个控件位中心layout_constraintCircleRadius
: 控件之间的距离layout_constraintCircleAngle
: 角度
Guideline
只能用于ConstraintLayout
中,是一个工具类,不会被显示,仅仅用于辅助布局。
它可以是horizontal
或者 vertical
的。(例如:android:orientation="vertical"
)
vertical
的Guideline
宽度为零,高度为ConstraintLayout
的高度horizontal
的Guideline
高度为零,宽度为ConstraintLayout
的高度定位Guideline
有三种方式:
layout_constraintGuide_begin
)layout_constraintGuide_end
)layout_constraintGuide_percent
)
看效果,就好像在整个constrainLayout的中部有一条竖直的分割线,而Button的右边位于guideLine的左边。其他的layout_constraintGuide_begin和layout_constraintGuide_end效果类似可以自己尝试一下。
当我们创建布局的时候,有时会遇到布局会随着本地化变化的情况。例如我们 有三个控件A,B,C。A ,内容为22...的控件,B为111....的控件,c为3333....的控件。如果要实现C控件相对于A B控件的右边放置。我们平常的做法就是,将A,B一起放在一个LinearLayout或者RelativeLayout中,然后将C 相对于整个布局容器放置。这就需要为 A ,B 放置一层外层的布局容器。就多了一层布局容器。用Barrier可以减少这一层布局。使得C 控件根据A,B 控件中宽度较大的哪一个 然后靠右,将C 放在宽度较大的哪一个的右边。
上述代码中 app:layout_constraintStart_toEndOf="@+id/barrier7" 的意思是将TextView3的开始放置在barrier7的右边。Barrier控件和guideline差不多,但是它可以接受多个控件的组合控制。属性 app:barrierDirection="end"。可以有几个其他的值,如下图,很容易理解。就字面意思。
group提供给我们另外一个便利,此类可以控制一组控件的可见性。控件以id标示,多个id之间用逗号隔开。我们可以使用group控制一组控件的可见性。