原文链接 Android ConstraintLayout运用攻略
ConstraintLayout是新一代的布局,它汲取了众家之长,把布局的概念进行了大统一,灵敏且强壮,基本上能够干掉以前一切的常用布局(LinearLayout, RelativeLayout和FrameLayout)。自从Android Studio 2.3(大约在2017年)后,它就变成了Android Studio的默许模板的布局控件,能够看出谷歌对它的宠爱程度。今天就来学习一下怎么运用这个新布局神器。
简述
ConstraintLayout与RelativeLayout有些相似,是一个布局管理器(ViewGroup),但要强壮许多,它能够以各种方法摆放子View,以及按份额伸缩。最重要的改动便是它关于『Drag and drop』拖拽式制作GUI页面支持的适当的好。当然了这个取决于个人喜好,很多人依然喜爱用写代码的方法直接去写xml文件,包含我在内。拖拽式虽然直观,可是不便利精准操控,关于一般性的布局来说尚可,但稍复杂了后,以及有了一些可滑动的view时,就不是那么的便利了。关于喜爱拖拽的同学能够查看官方的一个教程,以及郭大婶的一篇文章,这两篇专心于拖拽式,且讲的都比较详细。
添加依赖
由于ConstraintLayout并不是在标准的SDK中,而是被放在了support SDK中,现在统一叫androidx了,所以要单独添加依赖:
dependencies {
implementation 'com.android.support.constraint:constraint-layout:2.1.0'
}
概念与术语
ContraintLayout中把一切有关布局的参数都称之为Constraint(束缚),长和宽,对齐,居中,margin和padding都是constraint。布局中的属性均以”layout_constraint”为前缀。 束缚(Constrain)的意思是指用别的一个View(包含父布局即ContraintLayout)对当时View的某一布局参数施加影响。详细的影响叫做Constraint,别的一个View称作束缚目标(Constraining Object),当时View称作被束缚目标(Constrainted Object)。
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintLeft_toRightOf="@id/buttonA" />
摆放方法
对子View的摆放方法是一个ViewGroup的最根底的功用,它也体现了不同的布局管理器的效果,如线性布局(LinearLayout)是以水平或许垂直方向平铺方法来摆放子View的。ConstraintLayout是以相似RelativeLayout的方法,需求针对每个子View指定怎么摆放。
根底摆放方法
最为根底的摆放方法便是针对每个子View,指定它相关于别的一个View或许父布局(也便是ConstraintLayout本身)的相对方位,然后确认该View的详细方位。详细便是[left, top, right, bottom]四个要害的摆放元素相关于别的一个View或许父布局的方位联系。
如,layout_constraintLeft_toLeftOf=”parent”,这便是左面与父布局左面对齐;layout_constraintTop_toBottomOf=”id/header”,这是把这个View放在id为header的下面。以此类推,由于与RelativeLayout的布局参数比较相似,就不细说了,详情可参阅文档。
还有一个十分实用的Constraint叫做baseline,它是专门针对TextView的,baseline也即文本的基线,能够简略理解为文字的底部,当有两个TextiView不相同大,文字巨细也不相同时,却需求对齐文本,这个归于就适当的有用。
<TextView android:id="@+id/TextView1"/>
<TextView
android:id="@+id/TextView2"
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_constraintBaseline_toBaselineOf="@+id/TextView1"/>
margin
惯例运用与其他布局是相同的,经过layout_margin[Start,End,Left,Right,Bottom,Top]来指定与束缚目标之间的margin,这个不细说了。
需求说一下,ConstraintLayout有一个goneMargin,能够用于当一个束缚目标的Visibility被设置为GONE时,运用。用layout_goneMargin[Start,End,Left,Top,Right,Bottom]来设置。
比方A束缚B,B在A的右边,它俩挨着,但假如A的Visibility设置为GONE时,正常状况下B就会挨到本来A的左面了,跑到了左面界上,这时或许就会变得比较丑了,假如运用margin,比方在A和B中心加一个margin,能够处理问题,可是也会影响当A可见的时分。而用goneMargin就能够完美的处理此种场景。layout_goneMarginStart=”10dip”,那么这个margin只有当束缚目标A的Visibility被置为GONE时,才会收效,这时B虽然跑到了左面界上,可是还有margin,就不会那么丑了。(其实goneMargin运用的场景也比较有限,前面说的case,也能够用A和B的父布局的leftPadding来处理)
适当骚气的环状摆放方法
除了惯例的行列式摆放以外,这货还十分骚气的能够环状摆放,以束缚目标为圆心,经过视点和半径来束缚方位:
- layout_constraintCircle 用以指定作为圆心的束缚目标(其他view的id)
- layout_constraintCircleRadius 被束缚目标与圆心的距离
- layout_constraintCircleAngle 被束缚目标与横轴的视点(0~360度之间)
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="45" />
环状摆放实例
环状摆放虽然骚气,可是实际中好像运用场景不多。
居中与对齐
对齐不是大问题,前面讲的怎么摆放其实便是对齐,选定一个束缚目标后,其他目标都受其束缚,就天然对齐了。
比较常见的问题,以及大部分时分比较麻烦的是居中,平衡与中庸中契合绝大多数审美的,因而布局时,绝大多数状况下都是需求居中的。居中的完成的方法便是两头都束缚于父布局(也即ConstraintLayout),如:
<androidx.constraintlayout.widget.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</>
居中,其实便是两头的束缚边距各占空余空间的50%,扩展开来,想要完成不彻底居中,两头边距呈必定份额联系,也是能够办到的。比方说黄金份额0.618就比居中好看,这也好办:
<androidx.constraintlayout.widget.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintHorizontal_bias="0.382"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</>
这个份额操控叫bias,能够有Horizontal和Vertical两个方向。
尺度
尺度也便是针对子View的宽与高的束缚,其实大部分时分一些详细的子View的宽与高要么指定巨细,要么是WRAP_CONTENT的,但有些时分或许便是需求愈加的灵敏一些,这时就能够考虑用ConstraintLayout里边的一些特性。宽与高设置为固定巨细或许WRAP_CONTENT时与其他ViewGroup是相同的,不必多说,要想特别一点的便是设置为『0dip』或许MATCH_CONSTRAINT时,就会用其他束缚来决议该View的宽或许高。后边重点讨论有束缚的状况。
默许行为
假如子View的宽或许高设置为了MATCH_CONSTRAINT(或许『0dip』)时,默许的行为是它会占满剩下的可用空间。
Max与Min
还能够加上最大最小的限制:
- layout_constraintWidth_min and layout_constraintHeight_min : will set the minimum size for this dimension
- layout_constraintWidth_max and layout_constraintHeight_max : will set the maximum size for this dimension
- layout_constraintWidth_percent and layout_constraintHeight_percent : will set the size of this dimension as a percentage of the parent
按束缚目标的份额来设置(Percent)
前面的默许行为或许最大最小还算不上啥,其他ViewGroup也有相似参数。最为反常与强壮的是能够按束缚目标的份额来作为此View的宽或许高:
- The dimension should be set to MATCH_CONSTRAINT (0dp)
- The default should be set to percent app:layout_constraintWidth_default=”percent” or app:layout_constraintHeight_default=”percent”
- Then set the layout_constraintWidth_percent or layout_constraintHeight_percent attributes to a value between 0 and 1
本身宽高比(Ratio)
这个是最反常的束缚方法,能够设置一个本身的宽高比,以确认子View的尺度,当然了详细的宽或许高还要以其他束缚方法确认详细尺度,然后再按照设置的宽高比对别的一个进行束缚。比方,完成一个方形的按扭,宽是其本身要求的宽度值(WRAP_CONTENT),设置的宽高比是1:1,所以高度也会跟宽度相同,便是一个方形的按扭了:
<Button android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1" />
高级特性
前面讲的是一些根底运用方法,可是这货远不止这些,还有一些十分强壮的功用,下面简略介绍两个。
链(Chains)
在某一个方向上(横着或许竖着)有着彼此束缚的一组子View,会被视为一个链,第一个称作头部(Head),能够运用一些款式以对整个链内的子View都产生影响。
这儿的彼此束缚的意思是,比方有上面A,B,C三个子View,那么它们要彼此束缚,也即:
<ConstraintLayout>
<A layout_constraintLeft_toLeftOf="parent"
layout_constraintRight_toRightOf="B" />
<B layout_constraintLeft_toLeftOf="A"
layout_constraintRight_toRightOf="C" />
<C layout_constraintLeft_toLeftOf="B"
layout_constraintRight_toRightOf="parent" />
</ConstraintLayout>
就能够,对头部子View A进行款式(Chain style),经过layout_constraintHorizontal_chainStyle来设置:
- CHAIN_SPREAD — the elements will be spread out (default style)
- Weighted chain — in CHAIN_SPREAD mode, if some widgets are set to MATCH_CONSTRAINT, they will split the available space
- CHAIN_SPREAD_INSIDE — similar, but the endpoints of the chain will not be spread out
- CHAIN_PACKED — the elements of the chain will be packed together. The horizontal or vertical bias attribute of the child will then affect the positioning of the packed elements
链中的权重(Weighted chains)
默许状况下,子View会均分并占满可用的空间。能够用权重来按份额分配,给子View加上layout_constraintHorizontal_weight后,就会按份额分配,这个与LinearLayout的layoutWeight用法是相同的。
组(Groups)
为了View的烘托性能,各路大神告诉咱们要尽或许的让布局扁平化,可是,假如太扁平了,全都放在一个ViewGroup下面,就会紊乱,特别是像RelativeLayout和ConstraintLayout,子View的摆放方法会产生彼此依赖,会有牵一发起全身的状况出现。为了避免这种状况,就需求对子View进行分组,对页面进行区域划分,把紧密相关的视为一个组。以往,会用一个子ViewGroup把一个组包起来,虽然会加深View的层次,但这样能避免牵一发起全身。
而关于ConstraintLayout来说,有更先进的方法了,它有一个类叫Group,便是专门用来干这件事儿的,但Group目标并不是一个真的子View,这儿的意思是它并不会在View tree中进行烘托,它是专门用于管理归于它的子View的,比便利利对整个组进行Visibility的设置。
神器要怎么运用
前面的介绍就差不多了,ConstraintLayout还是适当的强壮的,如有或许还是尽或许的多用它吧。它的完成上面的确挺复杂的,毕竟功用比较强壮,但它的效率并不差。关于常用的几大布局都能够直接用它来代替。
当线性布局运用(as LinearLayout)
线性布局最大的优势就在于能够用weight的方法来按份额排放,而这个用前面提到的Chain就能够完美的处理。所以,LinearLayout能够彻底抛弃。
当层叠布局运用(as FrameLayout)
FrameLayout的全用场景一般是作为整个运用的根布局,特别是HomeActivity+Fragment这种架构。从纯的功用视点来讲,ConstraintLayout能够彻底完成FrameLayout的一切功用,所以,FrameLayout也能够抛弃。
但从简略便利视点来讲,假如是HomeActivity的根布局,子View都是MATCH_PARENT的Fragement的话,也没有必要换成ConstraintLayout,这种场景FrameLayout彻底够用,而且十分合适它。换成ConstraintLayout反倒有些糟蹋,有些杀鸡用牛刀。
当相对布局运用(as RelativeLayout)
早年面的叙述能够看出,ConstraintLayout简直便是RelativeLayout的加强版。所以,凡是用到RelativeLayout的当地都应该换成ConstaintLayout。
参考资料
- Build a Responsive UI with ConstraintLayout
- ConstraintLayout
- 束缚布局ConstraintLayout看这一篇就够了
- Use ConstraintLayout to design your Android views
- ConstraintLayout Tutorial for Android: Complex Layouts
- Constraint Layout Tutorial With Example In Android Studio
- Android新特性介绍,ConstraintLayout彻底解析