1、相对定位:
属性都形如 layout_constraint’DIRECTION’_to’TARGET DIRECTION’Of=”TARGET“
1、constraint’DIRECTION’ 里的 ‘DIRECTION’代表是这个子控件自身的哪条边
2、to’TARGET DIRECTION’Of 里的 ‘TARGET DIRECTION’ 代表的是和约束控件的哪条边发生约束
3、TARGET 为目标约束控件对应的 id(父控件的 id 理解为 parent)
2、Margin
1]注意点:
Note that a margin can only be positive or equals to zero, and takes a Dimension
1、只能为正值
2、必须指定维度
1)、只能为正值
当值设置为非正时,会使用默认值 0
margin 值对应的变量都在 LayoutParams 中
源码:
* ConstraintLayout#setChildrenConstraints 方法中设置 margin 相关代码
* 直接代码为:
2)、必须指定“维度”(横向或纵向)
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/fixed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="fixed"
android:layout_marginLeft="50dp"
android:layout_marginTop="50dp"
/>
</android.support.constraint.ConstraintLayout>
添加横向维度的“相对“约束时
app:layout_constraintLeft_toLeftOf="parent"
再添加纵向维度的”相对“约束时
app:layout_constraintTop_toTopOf="parent"
2] 要连接的控件 GONE 时 的 margin
layout_goneMargin’DIRECTION’
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/fixed"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="fixed"
android:visibility="visible"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="floating"
app:layout_constraintLeft_toRightOf="@+id/fixed"
app:layout_goneMarginLeft="120dp"
android:layout_marginTop="50dp"
app:layout_constraintTop_toTopOf="parent"
/>
</android.support.constraint.ConstraintLayout>
当 fixed button 设置为 gone 时
tips:在布局编辑器中,将 fixed 的 visibility 设置为 gone 时更容易看出效果
即使 target gone 了,但是其目标对象仍然没变,只不过目标由一个矩形变成一个点了
注意:这个点是 fixed 控件(也就是设置 layout_goneMarginXXX 属性的参照物) “缩小”形成的
这个点的(参照对 MATCH_CONSTRAINT 属性的解释)
* x 坐标是 fixed 控件满足横向约束范围的中间点;(如果 left 未设置参照,那么以 right 参照点为 x 坐标;如果 right 未设置参照,那么以 left 参照点为 x 坐标)
* y 坐标是 fixed 控件满足纵向约束范围的中间点(与 x 坐标同理)
下面这个例子是 left、right、top、bottom 都设置参照点的情况
上图中对应的 xml 为:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/btnFixed"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:text="Fixed"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btnFixedOther"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<Button
android:id="@+id/btnFixedOther"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
android:text="FixedOther"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btnFixed"
app:layout_goneMarginLeft="100dp"
app:layout_constraintBottom_toBottomOf="parent"
android:text="floating"
/>
</android.support.constraint.ConstraintLayout>
下面这个例子是 left、right、top 设置了参照点,而 bottom 未设置参照点的情况
上图中对应的 xml 为:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/btnFixed"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:text="Fixed"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btnFixedOther"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:id="@+id/btnFixedOther"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
android:text="FixedOther"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btnFixed"
app:layout_goneMarginLeft="100dp"
app:layout_constraintBottom_toBottomOf="parent"
android:text="floating"
/>
</android.support.constraint.ConstraintLayout>
3、居中定位和倾向
1)居中
控件的左边和父控件的左边对齐,控件的右边和父控件的右边对齐
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="button3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
/>
</android.support.constraint.ConstraintLayout>
对比
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="button3"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
/>
</RelativeLayout>
2)倾向(bias)
倾向的值的分配上可以类比 weight
- layout_constraintHorizontal_bias
(0最左边 1最右边) - layout_constraintVertical_bias
(0最上边 1 最底边)
例子:
<Button
android:layout_width="wrap_content"
android:layout_height="200dp"
android:text="floating"
app:layout_constraintHorizontal_bias="0.6"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintVertical_bias="0.7"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
注意:图中红色箭头只是辅助理解作用
横向:(目标值:0.6)
200 / (200 + 134) = 0.5988
248 / (248 + 183) = 0.5754
竖向:
1、
目标值:0.7
291 / (291 + 126) = 0.6978
402 / (402 + 238) = 0.6281
2、
目标值:0.8
332 / (332 + 83) = 0.8
444 / (444 + 197) = 0.69
4、尺寸约束
1)最小尺寸
对应属性为 wrap_content 时起作用
* android:minWidth
* android:minHeight
2)控件尺寸约束
- 确切的值
- wrap_content
- 0dp( match_constraint )
注意没有 match_parent
可以这么理解,也可以自己试一下,当某个方向上设置为 match_parent 时,对应方向上的所有约束都不再生效了,但是“约束布局”本身最重要的是约束
MATCH_CONSTRAINT
在对应的约束方向上充满“约束的最大范围”
约束的最大范围:
比如:(此处只说横向)
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/button1"
app:layout_constraintRight_toLeftOf="@+id/button4"
android:layout_height="wrap_content"
android:text="button2"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="80dp"
/>
预计:
约束的最大范围时两个红色箭头之间的距离(也就是两个虚线之间的范围)
实际:
再比如:
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/button1"
app:layout_constraintRight_toRightOf="parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/button2"
android:text="button3"
/>
预计:
约束的最大范围是两个红色箭头之间的距离(也就是两个虚线之间的范围)
实际:
5、比例
tips:至少一个约束维度设置为 0dp(MATCH_CONSTRAINT),并将 layout_constraintDimentionRatio 设定为给定的比例
比例可以为一个浮点数,或者 width:height
的形式
如果两个约束维度都不是 0dp ,那么比例设置无效
如果两个约束维度都是 0dp 时,系统会使用满足所有约束条件和比率的最大尺寸
6、链条
几个组件之间通过双向连接链接到一起时,可以认为这几个组件形成了链条
样式:
1、spread 分散开的
* 分散开的:(layout_constraintXXX_chainStyle 默认是此模式)
分散时包含组件外部
* 内部分散开的
分散时只包含组件内部
* (铺满)加权分散开的
有组件链条对应维度的大小设置为 0dp( MATCH_CONSTRAINT ) , 此时整个链条会铺满对应维度;
比如横向上有两个组件组成链条时:
2、packed 挤在一起的
tips:此模式下如果将组件的链条对应维度大小设置为 0dp( MATCH_CONSTRAINT ),那么设置0dp 的会不显示(注意与 spread 模式区分)
- 挤在一起的
默认居中 - 有偏向性的挤在一起的
只能由 head 组件指定倾向( bias )
7、Guideline
辅助 ConstraintLayout 的工具类
* vertical
纵向;宽度为零,高度为 ConstraintLayout 的高度
* horizontal
横向;高度为零,宽度为 ConstraintLayout 的高度
定位Guideline有三种方式:
* 指定距离左侧或顶部的固定距离(layout_constraintGuide_begin)
* 指定距离右侧或底部的固定距离(layout_constraintGuide_end)
* 指定在父控件中的宽度或高度的百分比(layout_constraintGuide_percent)
设置固定距离
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="100dp"
/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Button"
app:layout_constraintLeft_toLeftOf="@+id/guideline"
app:layout_constraintTop_toTopOf="parent"/>
设置百分比
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.6"
/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Button"
app:layout_constraintLeft_toLeftOf="@+id/guideline"
app:layout_constraintTop_toTopOf="parent"/>
同时设置固定距离和百分比
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.6"
app:layout_constraintGuide_begin="100dp"
/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Button"
app:layout_constraintLeft_toLeftOf="@+id/guideline"
app:layout_constraintTop_toTopOf="parent"/>
虽然显示 100,但是实际距离还是按照百分比算的,以下为原因
android.support.constraint.solver.widgets.Guideline
public void setGuidePercent(float value) {
if(value > -1.0F) {
this.mRelativePercent = value;
this.mRelativeBegin = -1;
this.mRelativeEnd = -1;
}
}
public void setGuideBegin(int value) {
if(value > -1) {
this.mRelativePercent = -1.0F;
this.mRelativeBegin = value;
this.mRelativeEnd = -1;
}
}
public void setGuideEnd(int value) {
if(value > -1) {
this.mRelativePercent = -1.0F;
this.mRelativeBegin = -1;
this.mRelativeEnd = value;
}
}
============================
动态
tips:一定注意最后要调用
ConstraintSet#applyTo
方法
1、ConstraintsSet 创建方式
- Manually
c = new ConstraintSet(); c.connect(....);
- from a R.layout.* object
c.clone(context, R.layout.layout1);
- from a ConstraintLayout
c.clone(clayout);
2、各属性对应代码:
1)相对定位
void connect (int startID, int startSide, int endID, int endSide, int margin)
Create a constraint between two widgets.
例如:xml
app:layout_constraintLeft_toLeftOf="parent"
对应代码:
constraintSet1.connect(R.id.tvTurn, ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.LEFT);
tips:如果设置某维度非居中的对齐方式,尽量把维度对应的另一个方向也设置上,设置为 UNSET
原因:之前控件为居中的,现在改为右对齐时,如果只设置一个方向,那么不会生效
如右对齐时:
constraintSetDemo.connect(R.id.demoView, ConstraintSet.LEFT, ConstraintSet.UNSET, ConstraintSet.LEFT);
constraintSetDemo.connect(R.id.demoView, ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT);
2、margin
基本规则与 xml 中一致
设置 margin 时遇到的问题:
表象:
涉及到左右 margin 的都无效
原因:
暂时不知道
Stack Overflow 上也有个类似问题,不过没人说是怎么回事,猜测是 bug
https://stackoverflow.com/questions/44129278/adding-constraints-to-a-view-in-a-constraintlayout-ignore-left-and-right-margins解决方式:
把 left 改成 start,right 改成 end,目前基本都是从左往右的;
比如
constraintSet3.setMargin(R.id.iconCompass, ConstraintSet.START, (int) ViewHelper.dpToPx(100, getApplicationContext()));