平时使用ConstraintLayout,断断续续的,基本都是在本身的小demo里面使用.公司的项目暂时尚未使用.此次公司项目须要大改,我决定用上这个nice的布局.减小嵌套(以前的老代码,实在是嵌套得太深了....无力吐槽).java
首先,ConstraintLayout是一个新的布局,它是直接继承自ViewGroup的,因此在兼容性方面是很是好的.官方称能够兼容到API 9.能够放心食用.android
先来看看下面一段简单示例:canvas
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮1"/>
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn1"
android:text="按钮2"/>
</android.support.constraint.ConstraintLayout>
复制代码
上面有一个简单的属性:layout_constraintLeft_toRightOf
,表示将按钮2放到按钮1的左边.若是没有这一句属性,那么两个按钮会重叠在一块儿,就像FrameLayout.bash
像这样的属性还有不少:app
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_constraintBaseline_toBaselineOf 基线对齐
layout_constraintStart_toEndOf 个人左侧与你的右侧对齐
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf
复制代码
上面的属性都很是好理解,除了一个相对陌生的layout_constraintBaseline_toBaselineOf
基线对齐.我们上代码:ide
<TextView android:id="@+id/btn1" android:text="按钮1" android:textSize="26sp"/>
<TextView android:id="@+id/btn2" android:text="按钮2" app:layout_constraintBaseline_toBaselineOf="@+id/btn1" app:layout_constraintLeft_toRightOf="@+id/btn1"/>
复制代码
一目了然,至关于文字的基线是对齐了的.若是没有加layout_constraintBaseline_toBaselineOf
属性,那么是下面这样的:函数
当须要子view放在父view的底部或者最右侧时. 咱们使用:布局
<android.support.constraint.ConstraintLayout app:layout_constraintEnd_toEndOf="parent">
<TextView android:text="按钮2" app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
复制代码
app:layout_constraintBottom_toBottomOf="parent" 个人底部与父亲底部对齐
app:layout_constraintTop_toTopOf="parent" 个人顶部与父亲的顶部对齐
app:layout_constraintLeft_toLeftOf="parent" 个人左侧与父亲的左侧对齐
app:layout_constraintRight_toRightOf="parent" 个人右侧与父亲的右侧对齐
复制代码
下面的TextView,与父亲左侧对齐,与父亲右侧对齐,因此,最右,它水平居中对齐.性能
<TextView app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"/>
复制代码
可能你也想到了,居中对齐其实就是2个对齐方式相结合.最后产生的效果. 好比:优化
这是垂直居中
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
复制代码
位于父亲的正中央
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
复制代码
边距和原来是同样的.
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
复制代码
举个例子:
<TextView android:id="@+id/btn1" android:text="按钮1" android:textSize="26sp"/>
<TextView android:id="@+id/btn2" android:text="按钮2" android:layout_marginStart="40dp" app:layout_constraintLeft_toRightOf="@+id/btn1"/>
复制代码
效果以下:
上面的水平居中,是使用的与父亲左侧对齐+与父亲右侧对齐. 能够理解为左右的有一种约束力,默认状况下,左右的力度是同样大的,那么view就居中了.
当左侧的力度大一些时,view就会偏向左侧.就像下面这样.
当咱们须要改变这种约束力的时候,须要用到以下属性:
layout_constraintHorizontal_bias 水平约束力
layout_constraintVertical_bias 垂直约束力
复制代码
来举个例子:
<android.support.constraint.ConstraintLayout
<Button
android:text="按钮1"
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
复制代码
能够看到,左右有2根约束线.左侧短一些.那么就偏向于左侧
翻译为:圆形的定位 ?
这个就比较牛逼了,能够以角度和距离约束某个view中心相对于另外一个view的中心,
可能比较抽象,来看看谷歌画的图:
他的属性有:
layout_constraintCircle :引用另外一个小部件ID
layout_constraintCircleRadius :到其余小部件中心的距离
layout_constraintCircleAngle :小部件应该处于哪一个角度(以度为单位,从0到360)
复制代码
举个例子:
<Button android:id="@+id/btn1" android:text="按钮1"/>
<Button android:text="按钮2" app:layout_constraintCircle="@+id/btn1" app:layout_constraintCircleRadius="100dp" app:layout_constraintCircleAngle="145"/>
复制代码
当一个View在ConstraintLayout中被设置为gone,那么你能够把它当作一个点(这个view全部的margin都将失效). 这个点是假设是实际存在的.
举个例子:
<Button
android:id="@+id/btn1"
android:text="按钮1"
android:textSize="26sp"/>
<Button
android:id="@+id/btn2"
android:layout_marginStart="20dp"
android:text="按钮2"
android:visibility="gone"
app:layout_constraintLeft_toRightOf="@+id/btn1"/>
<Button
android:id="@+id/btn3"
android:layout_marginStart="20dp"
android:text="按钮3"
app:layout_constraintLeft_toRightOf="@+id/btn2"/>
复制代码
能够看到,按钮3和按钮1中间的margin只有20.
再举个例子:
<Button android:id="@+id/btn2" android:layout_marginStart="20dp" android:text="按钮2" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/>
<Button android:id="@+id/btn3" android:text="按钮3" app:layout_constraintLeft_toRightOf="@+id/btn2" app:layout_constraintTop_toTopOf="@+id/btn2" app:layout_constraintBottom_toBottomOf="@+id/btn2"/>
复制代码
我将按钮3放到按钮2的右侧,这时是没有给按钮2加android:visibility="gone"
的.
如今咱们来给按钮2加上android:visibility="gone"
这时,按钮2至关于缩小成一个点,那么按钮3仍是在他的右侧不离不弃.
在ConstraintLayout中,能够给一个view设置最小和最大尺寸.
属性以下(这些属性只有在给出的宽度或高度为wrap_content时才会生效):
android:minWidth 设置布局的最小宽度
android:minHeight 设置布局的最小高度
android:maxWidth 设置布局的最大宽度
android:maxHeight 设置布局的最大高度
复制代码
平时咱们使用android:layout_width和 android:layout_height
来指定view的宽和高.
在ConstraintLayout中也是同样,只不过多了一个0dp.
下面是例子
<Button
android:id="@+id/btn1"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="按钮1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<Button
android:id="@+id/btn2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="按钮2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn1"/>
<Button
android:id="@+id/btn3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="60dp"
android:text="按钮3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn2"/>
复制代码
展现出来的是:
当一个view的宽或高,设置成wrap_content时,若是里面的内容实在特别宽的时候,他的约束会出现问题.咱们来看一个小栗子:
<Button android:id="@+id/btn1" android:layout_width="100dp" android:layout_height="wrap_content" android:text="Q"/>
<Button android:id="@+id/btn2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV" app:layout_constraintLeft_toRightOf="@id/btn1" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/btn1"/>
复制代码
从右侧的图片能够看出,按钮2里面的内容确实是在按钮1的内容的右侧.可是按钮2整个来讲,倒是没有整个的在按钮1的右侧.
这时须要用到下面2个属性
app:layout_constrainedWidth=”true|false”
app:layout_constrainedHeight=”true|false”
复制代码
给按钮2加一个app:layout_constrainedWidth="true"
,来看效果:
哈哈,又看到了咱们想要的效果.爽歪歪.
当一个view的长宽设置为MATCH_CONSTRAINT(即0dp)时,默认是使该view占用全部的可用的空间. 这里有几个额外的属性
layout_constraintWidth_min和layout_constraintHeight_min:将设置此维度的最小大小
layout_constraintWidth_max和layout_constraintHeight_max:将设置此维度的最大大小
layout_constraintWidth_percent和layout_constraintHeight_percent:将此维度的大小设置为父级的百分比
复制代码
这里简单举个百分比的例子:居中而且view的宽是父亲的一半
<Button android:id="@+id/btn1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="Q" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintWidth_percent="0.5"/>
复制代码
It's so easy! 这极大的减小了咱们的工做量.
注意
layout_constraintWidth_percent 或layout_constraintHeight_percent
属性设置为0到1之间的值能够设置View的宽高比例,须要将至少一个约束维度设置为0dp(即MATCH_CONSTRAINT
),再设置layout_constraintDimensionRatio
.
举例子:
<Button android:layout_width="0dp" android:layout_height="0dp" android:text="按钮" app:layout_constraintDimensionRatio="16:9" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/>
复制代码
该比率可表示为:
若是两个尺寸都设置为MATCH_CONSTRAINT(0dp),也可使用比率。在这种状况下,系统设置知足全部约束的最大尺寸并保持指定的纵横比。要根据另外一个特定边的尺寸限制一个特定边,能够预先附加W,“或” H,分别约束宽度或高度。例如,若是一个尺寸受两个目标约束(例如,宽度为0dp且以父节点为中心),则能够指示应该约束哪一边,经过 在比率前添加字母W(用于约束宽度)或H(用于约束高度),用逗号分隔:
<Button android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
复制代码
上面的代码将按照16:9的比例设置按钮的高度,而按钮的宽度将匹配父项的约束。
设置属性layout_constraintHorizontal_chainStyle或layout_constraintVertical_chainStyle链的第一个元素时,链的行为将根据指定的样式(默认值CHAIN_SPREAD)更改。
下面是一个相似LinearLayout的weight的效果,须要用到layout_constraintHorizontal_weight
属性:
<Button android:id="@+id/btn1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="A" app:layout_constraintEnd_toStartOf="@id/btn2" app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintHorizontal_weight="1" app:layout_constraintStart_toStartOf="parent"/>
<Button android:id="@+id/btn2" android:layout_width="0dp" android:layout_height="wrap_content" android:text="按钮2" app:layout_constraintEnd_toStartOf="@id/btn3" app:layout_constraintHorizontal_weight="2" app:layout_constraintStart_toEndOf="@id/btn1"/>
<Button android:id="@+id/btn3" android:layout_width="0dp" android:layout_height="wrap_content" android:text="问问" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_weight="3" app:layout_constraintStart_toEndOf="@id/btn2"/>
复制代码
例子的效果图以下:
这是一个虚拟视图
Guideline能够建立相对于ConstraintLayout的水平或者垂直准线. 这根辅助线,有时候能够帮助咱们定位.
layout_constraintGuide_begin 距离父亲起始位置的距离(左侧或顶部)
layout_constraintGuide_end 距离父亲结束位置的距离(右侧或底部)
layout_constraintGuide_percent 距离父亲宽度或高度的百分比(取值范围0-1)
复制代码
咱们拿辅助线干吗??? 好比有时候,可能会有这样的需求,有两个按钮,在屏幕中央一左一右. 若是是之前的话,我会搞一个LinearLayout,.而后将LinearLayout居中,而后按钮一左一右.
效果图以下:
如今咱们使用Guideline的话,就超级方便了,看代码:
<!--水平居中-->
<android.support.constraint.Guideline android:id="@+id/gl_center" android:layout_width="0dp" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.5"/>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮1" app:layout_constraintEnd_toStartOf="@id/gl_center"/>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮2" app:layout_constraintLeft_toRightOf="@id/gl_center"/>
复制代码
虚拟视图
Barrier是一个相似于屏障的东西.它和Guideline比起来更加灵活.它能够用来约束多个view.
好比下面的姓名和联系方式,右侧的EditText是确定须要左侧对齐的,左侧的2个TextView能够当作一个总体,Barrier会在最宽的那个TextView的右边,而后右侧的EditText在Barrier的右侧.
Barrier有2个属性
ps:这个东西有一个小坑,若是你写完代码,发现没什么问题,可是预览出来的效果却不是你想要的.这时,运行一下程序便可.而后预览就正常了,在手机上展现的也是正常的.
例子的代码以下(若是预览不正确,那么必定要运行一下,不要怀疑是本身代码写错了):
<TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="姓名:" app:layout_constraintBottom_toBottomOf="@id/tvTitleText"/>
<TextView android:id="@+id/tv_phone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="联系方式:" app:layout_constraintBottom_toBottomOf="@id/tvContentText" app:layout_constraintTop_toBottomOf="@+id/tv_name"/>
<EditText android:id="@+id/tvTitleText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="null" android:text="张三" android:textSize="14sp" app:layout_constraintStart_toEndOf="@+id/barrier2"/>
<EditText android:id="@+id/tvContentText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="null" android:text="xxxxxxxxxxxxxxx" android:textSize="14sp" app:layout_constraintStart_toEndOf="@+id/barrier2" app:layout_constraintTop_toBottomOf="@+id/tvTitleText"/>
<android.support.constraint.Barrier android:id="@+id/barrier2" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="right" app:constraint_referenced_ids="tv_name,tv_phone"/>
复制代码
固定思议,这是一个组. 这也是一个虚拟视图.
能够把View放到里面,而后Group能够同时控制这些view的隐藏.
<android.support.constraint.Group android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" app:constraint_referenced_ids="btn1,btn2"/>
<Button android:id="@+id/btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮1"/>
<Button android:id="@+id/btn2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮2" app:layout_constraintTop_toBottomOf="@id/btn1"/>
复制代码
constraint_referenced_ids
,能够将那些须要同时隐藏的view丢进去.上面咱们列举的虚拟视图一共有:
来咱们看看源码
//Guideline
public class Guideline extends View {
public Guideline(Context context) {
super(context);
//这个8是什么呢?
//public static final int GONE = 0x00000008;
//实际上是View.GONE的值
super.setVisibility(8);
}
public Guideline(Context context, AttributeSet attrs) {
super(context, attrs);
super.setVisibility(8);
}
public Guideline(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
super.setVisibility(8);
}
public Guideline(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr);
super.setVisibility(8);
}
//可见性永远为GONE
public void setVisibility(int visibility) {
}
//没有绘画
public void draw(Canvas canvas) {
}
//大小永远为0
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
this.setMeasuredDimension(0, 0);
}
复制代码
咱们看到Guideline实际上是一个普通的View,而后在构造函数里将本身设置为GONE
综上所述,我以为这个Guideline就是一个不可见的且不用测量,不用绘制,那么咱们就能够忽略其绘制消耗.
而后Barrier和Group都是继承自ConstraintHelper的,ConstraintHelper是一个View.ConstraintHelper的onDraw()和onMeasure()以下:
public void onDraw(Canvas canvas) {
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//mUseViewMeasure一直是false,在Group中用到了,可是仍是将它置为false了.
if (this.mUseViewMeasure) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} else {
this.setMeasuredDimension(0, 0);
}
}
复制代码
哈哈,实际上是和Guideline同样的嘛,仍是能够忽略其带来的性能消耗嘛.上面的mUseViewMeasure一直是false,因此长宽一直为0.
因此咱们能够将Guideline,Barrier,Group视为虚拟试图,由于它们几乎不会带来多的绘制性能损耗.我是这样理解的.
能够经过将标签app:layout_optimizationLevel元素添加到ConstraintLayout来决定应用哪些优化。这个我感受还处于实验性的阶段,暂时先别用..哈哈
使用方式以下:
<android.support.constraint.ConstraintLayout
app:layout_optimizationLevel="standard|dimensions|chains"
复制代码
我把一些经常使用的属性和怎么用都列举出来,方便你们查阅.若有不对的地方,欢迎指正.