约束布局解析

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()));

猜你喜欢

转载自blog.csdn.net/lonewolf521125/article/details/78460934
今日推荐