译为”约束布局“, 是Google在AndroidStudio2.2引入的布局. 在AndroidStudio 2.3直接替代了之前的Activity创建的默认布局RelativeLayout. 可以看到Google对其重视性.
特点
注意: 本文讲解的ConstraintLayout是在1.0.2正式版的前提下. 这个布局后续肯定是会频繁更新的, 出入是会存在的.
官方文档
ConstraintLayout的最大特点就是很好的支持AndroidStudio的布局编辑器. 之前的布局其实也支持布局编辑器, 但是效果很差, 所以都使用XML编辑代码.
布局编辑器左边有个面板, 用于拖控件到布局编辑器中
在布局编辑器的左边就是全部的控件列表. 可以通过直接拖动到布局预览界面来创建视图控件. 并且不需要你手动导入依赖包.
依次介绍:
顺序依次
预览图主要显示手机的实际效果(ConstraintLayout拥有布局编辑器属性, 所以存在预览界面和实际应用不同的情况), 蓝图主要清晰显示布局的信息
两者都可以直接编辑布局, 看你的喜好.
这一栏是根据你选择的ViewGroup变化的布局属性栏, 这里我只介绍ConstraintLayout的布局属性栏, 其他的没什么好介绍的一看就知道了.
依次功能:
这个类似磁铁的图标如果处于开启状态. 控件只要一拖到布局编辑器中就会自动创建水平和垂直方向各一条约束.
该功能属于一次性功能, 点击一次就会自动计算并且给当前布局编辑器中所有没有进行约束处理的控件进行水平和垂直方向各一条约束.
这个功能其实就相当于PS或者说很多作图工具中的一个辅助线
除了布局编辑器写布局也应该要了解布局的属性, 不然有些问题你看不出来的.
该属性并不会在Android上有任何影响, 只会影响AS的布局编辑器坐标
tools:layout_editor_absoluteY="246dp"
tools:layout_editor_absoluteX="36dp"
布局编辑器
真机上
一个控件有四个约束点/ 十二个约束属性(左和右有各有两个属性start和end以及right和left)
约束只能是同一水平下才能相互约束, 例如左和右之间能约束, 左不能和上下约束点关联.
约束并不是相互关联的关系. 而是
// 和父布局关联约束
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
// 和其他控件关联约束
app:layout_constraintLeft_toRightOf="@+id/button3"
app:layout_constraintRight_toLeftOf="@+id/button3"
app:layout_constraintTop_toBottomOf="@id/button3"
app:layout_constraintBottom_toTopOf="@id/button3"
layout_constraintStart_toEndOf
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf
有些控件是包含文字内容的, 所以约束布局的控件有一个文字基准线约束. 默认是隐藏,需要点击开关显示.
layout_constraintBaseline_toBaselineOf
注意: 使用了文字基准线对齐就不需要使用上下约束了
通过小数点(百分比)控制控件在屏幕垂直/水平的百分比位置.
注意: 只有水平位置(上下/左右约束点都添加了约束)都添加约束, 该控件才支持百分比偏移
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintVertical_bias="0.69"
注意: 如果是约束的ConstraintLayout, 不需要这两个属性也可以设置百分比偏移
一般的边距没什么好讲的. 和以前一样.
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
因为约束布局控件之前的关联性太强, 如果一个布局隐藏(gone)就可能导致整个布局的位置移动. 所以ConstraintLayout拥有隐藏边距属性
ConstraintLayout中使用Gone属性值
根据官方图可以看出Constraintlayout如果控件被隐藏并不会像其他布局一样坐标变成0,0点. 只是margin和宽高变成0.
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
以上边距属性会根据其约束的控件是否是隐藏(invisible不算)来生效, 同时margin失效.
通过设置宽或者高中的一个为match_constraint(0dp), 就可以设置控件的宽高比
matc_constraint的宽或高会根据另一边的尺寸变化来符合比例
宽高比分两种:
宽:高
app:layout_constraintDimensionRatio="2:1"
很简单就是宽比高, 默认受约束的就是**非**match_constraint(0dp)的一边.
受约束的是不会发生尺寸变化(如果是match_constraint和wrap_content时1:1比例会发生尺寸变化成正方形)
这一种我有点不太能理解, 官方感觉解释也比较模糊.
app:layout_constraintDimensionRatio="w,2:1"
我理解为颠倒了比例. w即设置比例为宽高, h为高比宽. 实际操作体验吧
辅助线用户是不可见的, 也没有宽高参数(你给他设置也无效). 只是在约束布局中做一个相对基准线而已.
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline2"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.41"
/>
辅助线有三种属性
app:layout_constraintGuide_begin="20dp"
app:layout_constraintGuide_end="340dp"
app:layout_constraintGuide_percent="0.055555556"
辅助线有水平和垂直两种:
宽高属性值
理论上ConstraintLayout的宽高不再使用match_parent
这一属性值. 取而代之的是0dp(称为match_constraint).
Important:
MATCH_PARENT
is not supported for widgets contained in aConstraintLayout
, though similar behavior can be defined by usingMATCH_CONSTRAINT
with the corresponding left/right or top/bottom constraints being set to"parent"
.
官方说明match_parent在ConstraintLayout中不被支持
match_constraint只有在水平或者垂直拥有两条方向的约束时才有效, 即匹配剩余全部空间. 如果只有水平只存在一条或者没有约束相当于wrap_content.
示例图:
如果你强行使用编辑器会自动帮你转换成固定dp值, 不过如果你仅仅是约束ConstraintLayout布局并没有问题.不能理解我说的什么自己动手试试.
两个空间相互约束就会产生一个锁链. (注意布局编辑器中是无法通过拖动约束点相互约束, 我认为是bug)
只能通过多选居中的方式或者直接XML编辑.
app:layout_constraintHorizontal_chainStyle="packed"
链接在一起主要是可以设置不同的样式达到适配父容器宽度或者高度的效果. 注: 一个链还有第一个控件才需要设置(chainStyle)样式.
根据样式有三种参数值:
官方有一张介绍图
虽然看着有五个,实际上属性还是那三个. 不过有加入权重和百分比偏移. Bias是偏移, weighted是权重.
和LinearLayout的wight属性一样. 不过只支持spread和spread_inside有效.
layout_constraintHorizontal_weight
同样可以编辑属性也可以鼠标修改
ConstraintLayout如果想对布局进行修改就必须使用到该类ConstraintSet. 对于常见的布局属性就不介绍了.
步骤:
示例:
public class MainActivity extends AppCompatActivity {
ConstraintSet mConstraintSet = new ConstraintSet(); // create a Constraint Set
ConstraintLayout mConstraintLayout; // cache the ConstraintLayout
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.state1);
Context context = this;
mConstraintLayout = (ConstraintLayout) findViewById(R.id.activity_main);
mConstraintSet.clone(mConstraintLayout); // 克隆一个布局到ConstraintSet
}
public void onClick(View view) {
TransitionManager.beginDelayedTransition(mConstraintLayout); // 一行代码添加动画
mConstraintSet1.applyTo(mConstraintLayout); // 应用到新的布局
}
}
void clear (int viewId,
int anchor)
void clear (int viewId)
void setAlpha (int viewId,
float alpha)
旋转中心是控件的中心
void setRotationX (int viewId,
float rotationX)
void setRotationY (int viewId,
float rotationY)
同样是以控件为中心, 百分比浮点数
void setScaleX (int viewId,
float scaleX)
void setScaleY (int viewId,
float scaleY)
以控件中心偏移(不知道为何我写无效)
void setTransformPivot (int viewId,
float transformPivotX,
float transformPivotY)
void setTransformPivotX (int viewId,
float transformPivotX)
void setTransformPivotY (int viewId,
float transformPivotY)
void setMargin (int viewId,
int anchor,
int value)
void applyTo (ConstraintLayout constraintLayout)
复制一个ConstraintLayout布局到ConstraintSet中. 后面可以对ConstraintSet进行修改(即对复制的布局修改).
void clone (ConstraintSet set)
void clone (ConstraintLayout constraintLayout)
void clone (Context context,
int constraintLayoutId)
不用Clone直接加载一个XML布局文件.
void load (Context context,
int resourceId)
void connect (int startID,
int startSide,
int endID,
int endSide,
int margin)
主要介绍一些可能是Bug或者是我知识层面不够的问题
如果你使用了infer Constraint会发现自动生成了很多以tools开头的属性, 这些属性不用去管, 不对应用有任何影响.
tools:layout_constraintTop_creator="1"
主要是因为控件存在两个左右边距属性(start和left或者right和end)
删除start或者end即可. 个人认为是bug, 已经提交给Google.
要想使用Chain两个控件必须相互约束, 但是布局编辑器中无法相互约束
但是XML直接编辑或者以下方法还是可以相互约束的, 所以个人认为是bug
如果出现控件不在编辑器内显示, 请检查编辑器属性坐标.
tools:layout_editor_absoluteX="137dp"
tools:layout_editor_absoluteY="-118dp"