ConstraintLayout 使用详解,减少嵌套 UI, 提升性能

news2024/11/18 3:34:07

前言

对于初学者来说,可能觉得ConstraintLayout属性多,且属性长而弃用它,那你错失了这个大宝贝。

因为在复杂布局,我们会一直用RelativeLayout和LinearLayout去嵌套,因为嵌套的ViewGroup会导致手机多次测量和绘制,从而影响性能,如果嵌套严重可能出现掉帧或卡顿。

使用ConstraintLayout一招入魂。一句话概括是:传统布局能实现的,它能轻松实现实现。传统布局不能实现的,它也能实现。

一、为什么要用呢?

这里举个2个简单的例子。

1.1、例1

如图下图所示,我们分别用RelativeLayout和ConstraintLayout去实现它:

1.png

1.1.1、使用RelativeLayout实现如下

<RelativeLayout...>


    <TextView
        android:id="@+id/txt_a"
        android:layout_centerHorizontal="true"
        .../>

    <RelativeLayout
        android:layout_alignTop="@+id/txt_a"
        android:layout_toLeftOf="@+id/txt_a"
        android:layout_alignBottom="@+id/txt_a"
        ...>

        <TextView
            android:layout_centerInParent="true"
            android:id="@+id/txt_b"
            .../>

    </RelativeLayout>


</RelativeLayout>

这里使用了伪代码,把无关紧要的属性去掉了。相信懂的人都明白。这里用图层表示下,如下:

2.png

  • 最外层是 RelativeLayout(根布局)
  • 红色TextView_A 在顶部且横向居中。
  • 使用绿色 RelativeLayout上边和下边和A齐平,从而保证绿色RelativeLayout高度和A一样。且宽度满屏,在A左边
  • 蓝色TextView_B 在绿色RelativeLayout里居中。

那么接下来看看ConstraintLayout如何实现?

1.1.2、使用ConstraintLayout实现如下

<androidx.constraintlayout.widget.ConstraintLayout...>

    <TextView
        android:id="@+id/txt_a"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        .../>

    <TextView
        app:layout_constraintRight_toLeftOf="@+id/txt_a"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="@+id/txt_a"
        app:layout_constraintBottom_toBottomOf="@+id/txt_a"
        android:id="@+id/txt_b"
        .../>

</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

我们继续看下,他的图层关系,真的简洁。

3.png

1.2、例2

如图下图所示,我们分别用RelativeLayout和ConstraintLayout去实现它:

4.png

在xml里。我们无法用RelativeLayout去实现,如下分析

  • B在A下方,通过 android:layout_below="@+id/txt_a"实现
  • B要在A底部边框上,垂直居中。那么我们要知道B的height。B再使用marginTop="-height/2"才能达到效果。所以在xml里无法实现,只能去代码里动态计算。

使用ConstraintLayout则可轻松完成:

<androidx.constraintlayout.widget.ConstraintLayout ...>


    <TextView
        android:id="@+id/txt_a"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        .../>

    <TextView
        app:layout_constraintRight_toRightOf="@+id/txt_a"
        app:layout_constraintLeft_toLeftOf="@+id/txt_a"
        app:layout_constraintTop_toBottomOf="@+id/txt_a"
        app:layout_constraintBottom_toBottomOf="@+id/txt_a"
        android:id="@+id/txt_b"
        .../>

</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

上面只是简单的2个小例子,实战上在复杂布局里,真的有太多好处。接下我们具体说说把。

二、ConstraintLayout各属性介绍

2.1、相对定位

2.1.1、例1,如图:靠右边

5.png

实现如图功能:

<TextView
    ...
    app:layout_constraintRight_toRightOf="parent"
    />
复制代码

layout_constraintRight_toRightOf 属性还有left、right、top、bottom、start、end等搭配使用。什么意思呢?

  • 第一个Right代表 本控件的右边
  • 第二个Right代表 要位于目标控件右边。
  • 所以app:layout_constraintRight_toRightOf=“parent”; 红色A的右边位于父容器的右边

注意start、end是因为很多国家阅读习惯不一样,比如我们是习惯从左往右阅读。所以start对于我们来说就是left,end就是right。


2.1.2、例2,如图:居中

6.png

实现如图功能:

<TextView
    ...
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    />
复制代码

右边和父控件右边对齐,左边和父控件左边对齐。这样就可以达到横向居中,同理竖直。

注意这里居中了。同样还可以用margin进行偏移。也可以利用属性app:layout_constraintHorizontal_bias=“0.5”,进行横向偏移,0.5意思也还算居中。同理竖直的属性。


2.1.3、例3,如图:充满屏幕

7.png

比如B要在A的右边,且相对A上下居中,而且B要充满剩余横屏:

<TextView
    app:layout_constraintLeft_toRightOf="@+id/txt_a"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="@+id/txt_a"
    app:layout_constraintBottom_toBottomOf="@id/txt_a"
    android:layout_width="0dp"
    ...
    />
复制代码

要想充满全屏把宽度设置为0dp。然后通过以下代码:

  • app:layout_constraintLeft_toRightOf=“@+id/txt_a”;B的左边和A的右边对齐
  • app:layout_constraintRight_toRightOf=“parent”;B的右边和父容器的右边对齐

这样B就在A的右边,且横向充满屏。注意:在约束布局里match_parent是不生效的。

要想B竖直方向与A平行的话,通过如下代码:

  • app:layout_constraintTop_toTopOf=“@+id/txt_a”;B的上边和A的上边对齐
  • app:layout_constraintBottom_toBottomOf=“@id/txt_a”;B的下边和A的下边对齐

这样就可以让B在A右边,上下居中。


2.1.4、例4,如图:不嵌套居中

8.png

在列表里我们经常会遇到这样的需求,A是一张图片,title是标题,des是描述。用RelativeLayout的做法是:继续用一个layout布局包裹title和des,居中然后放在A的右边。

用ConstraintLayout的话不用嵌套,3个view就搞定了。如下:

<ImageView
    ...
    />


<TextView
    app:layout_constraintTop_toTopOf="@+id/image"
    app:layout_constraintBottom_toTopOf="@+id/txt_des"
    android:id="@+id/txt_title"
    ...
    />

<TextView
    app:layout_constraintTop_toBottomOf="@+id/txt_title"
    app:layout_constraintBottom_toBottomOf="@+id/image"
    
   * 这个时候你会发现还没有居中因为还缺了一条约束,title在des上边;
    android:id="@+id/txt_des"
    ...
    />
复制代码

因为例3,已经讲过如何全屏了,这里主要讲title和des如何居中:

  • des 在title下面;app:layout_constraintTop_toBottomOf=“@+id/txt_title”
  • title上边和图片A上边对齐;app:layout_constraintTop_toTopOf=“@+id/image”
  • des下边和图片A下边对齐;app:layout_constraintBottom_toBottomOf=“@+id/image”
  • 这个时候你会发现还没有居中因为还缺了一条约束,title在des上边; app:layout_constraintBottom_toTopOf=“@+id/txt_des”,这和RelativeLayout有些区别

这里还有一个属性文本基线对齐,和RelativeLayout里的 layout_alignBaseline 是一样的效果

  • app:layout_constraintBaseline_toBaselineOf=“@+id/txt_a”

关于相对定位已经讲完了。

2.2、角度定位

如图:

9.png

实现代码如下:

<TextView
    android:id="@+id/txt_a"
    ...
     />

<TextView
    app:layout_constraintCircle="@+id/txt_a";
    app:layout_constraintCircleAngle="90"
    app:layout_constraintCircleRadius="100dp"
    android:id="@+id/txt_b"
    ...
    />
复制代码
  • app:layout_constraintCircle=“@+id/txt_a”;B相对于A角度定位
  • app:layout_constraintCircleAngle=“90”;角度定位角度为90°
  • app:layout_constraintCircleRadius=“100dp”;B中心与A中心相差100dp

这个时候我也在想有什么用呢?我觉得可以用在某些自定义view上。比如圆形menu、实现时钟更简单了。我用属性动画,实现一个效果你就明白了。录制有点卡顿,真机不会…

GIF.gif

2.3、边距

2.3.1、margin

margin 值要生效,一定是伴随约束属性的。什么意思呢,要实现如图功能:

10.png

代码实现如下:

<TextView
    android:id="@+id/txt_a"
    ...
     />

<TextView
    android:layout_marginLeft="20dp"
    app:layout_constraintLeft_toRightOf="@+id/txt_a"
    android:id="@+id/txt_b"
    ...
     />
复制代码
  • 比如B左边和A的右边对齐app:layout_constraintLeft_toRightOf=“@+id/txt_a”,此时在B上加上margin值生效
  • 如果这个时候在A上加上android:layout_marginRight=“50dp”,是不生效的。谨记

2.3.2、goneMargin

goneMargin属性比较有意思。比如要实现如下功能,从图1–>图2:

图1如下:

11.png

图2如下:

12.png

隐藏A的时候B要置顶排布。在RelativeLayout里,我们只需要在A里使用Margin_Bottom=“20dp”,然后对A进行隐藏就可以实现了。但是在ConstraintLayout里,因为margin生效必须要有约束,所以这个时候B就要使用goneMargin属性,实现代码如下:

<TextView
    android:id="@+id/txt_a"
    android:visibility="gone"
    ...
     />

//意思就是当有约束的控件隐藏时,goneMargin就会生效,那么B就会置顶排布。
<TextView
    android:id="@+id/txt_b"
    app:layout_constraintTop_toBottomOf="@+id/txt_a"
    android:layout_marginTop="20dp"
    app:layout_goneMarginTop="0dp"
    ...
     />
复制代码

2.4、尺寸

在ConstraintLayout里,设置尺寸大小的有3个:

  • 设置固定的dp值
  • wrap_content
  • 0dp(MATCH_CONSTRAINT),前面讲过match_parent是不生效的。如果想达到match_parent的效果只能通过0dp和约束来达到。

2.4.1、满屏

比如控件A满屏(在2.1.3一样),如下效果:

13.png

则通过如下代码实现:

<TextView
    android:layout_width="0dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    ...
    />
复制代码

2.4.2、layout_constraintWidth_max

属性 layout_constraintWidth_max 在使用dp固定值的时候和 android:maxWidth=“100dp” 用法是一致的。

但是layout_constraintWidth_max可以搭配属性 app:layout_constraintWidth_percent=“0.5” 使用,什么意思呢。

比如我们要实现红色区域占父容器宽度的一半:

14.png

实现代码如下:

<TextView
    app:layout_constraintLeft_toLeftOf="parent"
    android:layout_width="0dp"
    android:text=""
    app:layout_constraintWidth_max="wrap"
    app:layout_constraintWidth_percent="0.5"
    ...
     />
复制代码

这里这样设置的时候,意思最大宽度是父容器的一半。注意这里text=""空的时候,会像图中直接展示父容器的一半,假设我们给text="A"设置上值后,如下图,那么只会展示A的宽度,但最大宽度是父容器一半。

15.png


2.4.3、app:layout_constrainedWidth

app:layout_constrainedWidth=“true” 属性,是按约束去限制宽度,什么意思呢?我们先不加上这条属性,实现如下图效果是这样的:

16.png

代码是这样的:

<TextView
    android:id="@+id/txt_a"
    ...
     />


<TextView
    app:layout_constraintLeft_toLeftOf="@id/txt_a"
    app:layout_constraintRight_toRightOf="@id/txt_a"
    app:layout_constraintTop_toBottomOf="@+id/txt_a"
    android:id="@+id/txt_b"
    android:layout_width="wrap_content"
    android:text="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
    ...
     />
复制代码

给txt_b加上 app:layout_constrainedWidth=“true” 属性后,就会实现下面的效果:

17.png

意思就是B的最大宽度按照A的宽度来约束,这里要注意的是,B的宽度是wrap_content。假设这里是0dp的话,那这里就另外一种情况了,意思就是B的宽度和A的宽度一样宽。


2.4.4、layout_constraintDimensionRatio 宽高比

app:layout_constraintDimensionRatio=“1:1”,宽高比,注意这一条属性要生效的话要达到2个条件:

  • 其中一条边为0dp
  • 其中一条边为固定值或wrap_content

比如要实现如下,一个正方形的A:

18.png

代码如下:

<TextView
    android:id="@+id/txt_a"
    android:layout_width="0dp"
    android:layout_height="50dp"
    app:layout_constraintDimensionRatio="1:1"
    ...
    />
复制代码

2.5、链/约束.

指多个控件在一条方向上相互约束,形成一条链子似的。(这里还不算是线性布局, 因为还没加权重) 比如实现如下:

19.png

代码如下:

<TextView
    android:id="@+id/txt_1"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/txt_2"
    ...
    />

<TextView
    android:id="@+id/txt_2"
    app:layout_constraintLeft_toRightOf="@+id/txt_1"
    app:layout_constraintRight_toLeftOf="@id/txt_3" 
    ...
    />

<TextView
    android:id="@+id/txt_3"
    app:layout_constraintLeft_toRightOf="@id/txt_2"
    app:layout_constraintRight_toRightOf="parent"
    ...
    />
复制代码

这样就在横向方向形成一条链子了(同理纵向),在一条链子的第一个控件也就是链头,我们可以加上layout_constraintHorizontal_chainStyle来改变整条链的样式,有3中

  • spread就是上面的样子
  • spread_inside

20.png

  • packed

21.png


上面的降的宽度都是wrap_content,如果我们把宽度设置为0do然后通过属性layout_constraintHorizontal_weight(同理纵向),加上权重后,就是我们的线性布局。比如实现如下:

22.png

代码:

<TextView
    android:id="@+id/txt_1"
    android:layout_width="0dp"
    app:layout_constraintHorizontal_weight="2"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/txt_2"
    ...
    />

<TextView
    android:id="@+id/txt_2"
    android:layout_width="0dp"
    app:layout_constraintHorizontal_weight="1"
    app:layout_constraintLeft_toRightOf="@+id/txt_1"
    app:layout_constraintRight_toLeftOf="@id/txt_3"
    ...
    />

<TextView
    android:id="@+id/txt_3"
    android:layout_width="0dp"
    app:layout_constraintHorizontal_weight="1"
    app:layout_constraintLeft_toRightOf="@id/txt_2"
    app:layout_constraintRight_toRightOf="parent"
    ...
    />
复制代码

2.6、辅助工具

2.6.1、Guideline

guideline和辅助先一样,运行项目的时候,不会显示在界面上。也不用担心会消耗性能,因为在其onDraw方法里,没有具体的实现。guideline属性具体如下:

  • android:orientation=“vertical” 纵向辅助线,同理横向
  • 然后就是确定辅助线的位置,通过下面3个属性,多个出现时只会有一个生效,权重是百分比 > begin > end

app:layout_constraintGuide_percent=“0.5” 在父布局的百分比位置
app:layout_constraintGuide_begin=“10dp” 距离父布局开始位置,横向为左,纵向为顶部
app:layout_constraintGuide_end=“10dp” 距离父布局末尾位置

比如我们之前经常会写 时间轴 类似的控件。就可以用这个guideline辅助完成。

23.png

2.6.2、Barrier

24.png

假设有3个控件A、B、C,如果我们A,B的宽度不固定,同时又希望C在A,B的右边。如果用一个布局把A,B包裹起来,然后让C在A,B右边可以实现,如果不像嵌套就要通过Barrier了,如下图:

25.png

实现代码如下:

<TextView
    android:id="@+id/txt_1"
    ...
    />

<TextView
    android:id="@+id/txt_2"
    app:layout_constraintTop_toBottomOf="@+id/txt_1"
    ...
    />

<androidx.constraintlayout.widget.Barrier
    android:id="@+id/barrier"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:barrierDirection="right"
    app:constraint_referenced_ids="txt_1,txt_2" />

<TextView
    android:id="@+id/txt_3"
    app:layout_constraintLeft_toRightOf="@+id/barrier"
    ...
    />
复制代码

Barrier属性有:

  • app:barrierDirection=“right” 为屏障时,哪个方向的屏障,图中是A和B的右边
  • app:constraint_referenced_ids=“txt_1,txt_2” 为屏障引用的id,用逗号隔开

注意,这里是为减少布局嵌套。必要时我觉得可以灵活运用嵌套。

2.6.3、Group

被布局Layout嵌套的控件A,B,我们要隐藏他只需要隐藏这个嵌套布局Layout即可。在ConstraintLayout里,没有了布局嵌套隐藏A,B就通过Group实现:

<androidx.constraintlayout.widget.Group
    android:visibility="gone"
    android:id="@+id/group"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:constraint_referenced_ids="txt_1,txt_2"
    />
复制代码

2.6.4、Placeholder:小重点。

网上很多资料对这Placeholder都一比带过。看了我这里的介绍,你会更清楚怎么使用Placeholder。

Placeholder从名字看,就是占位的意思。你可以在一个页面设置多个不同位置的占位。然后通过代码setContentId直接可以改变某个view移动到我们的占位图里。什么意思呢。请看下图:

GIF222.gif

我在界面上设置了2个Placeholder。通过2个按钮,控制蓝色TextView处于在哪个PlaceHolder里。

  • 首先通过app:content=“@+id/txt_blue”,让蓝色textView默认在placeholder_1的位置。
  • 注意蓝色textView还是需要在xml里的。
<TextView
    android:id="@+id/txt_red"
    ...
     />


<androidx.constraintlayout.widget.Placeholder
    android:id="@+id/placeholder_1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/txt_1"
    app:content="@+id/txt_blue"
    />

<TextView
    android:id="@+id/txt_green"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/placeholder_1"
    ...
    />

<androidx.constraintlayout.widget.Placeholder
    android:id="@+id/placeholder_2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />


<TextView
    android:id="@+id/txt_blue"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    ...
     />
复制代码

2个按钮我没写上去懂的都懂,那2个按钮上的代码呢?注意看了。这可能是google还没有解决这话bug。下面我来说下

  • 当点击按钮“在位置2里”,把蓝色textView放进placeholde_2,通过placeholde_2.setContentId(R.id.txt_2);
  • 注意此时placeholde_1还是占据着蓝色textView的高度。
  • 当点击“在位置1里”,我们首先要把placeholde_2里蓝色TextView的引用清空掉,用placeholde_2.setContentId(-1);
  • 因为placeholde_1有之前蓝色TextView的引用,虽然是同一个东西,但是设置会不生效。必须清楚掉之前的引用(看源码得出来的结果)。通过placeholde_1.setContentId(-1);
  • 最后通过placeholde_1.setContentId(R.id.txt_2);就可以使蓝色textView又回到了placeholde_1身上了

具体代码如下:

findViewById(R.id.buttonPanel).setOnClickListener(v ->{
    placeholde_2.setContentId(R.id.txt_2);
});


findViewById(R.id.buttonPane2).setOnClickListener(v ->{
    placeholde_2.setContentId(-1);
    placeholde_1.setContentId(-1);
    placeholde_1.setContentId(R.id.txt_2);
});
复制代码

如果这个时候,我们想只要Placeholder移除了蓝色TextView。我们就让Placeholder也隐藏不可见。其实是有办法的。

  • 步骤1:给Placeholder加上属性app:placeholder_emptyVisibility=“gone”。
  • 步骤2:除了以上步骤,我们还要搭配setContentId(-1),才可以实现效果。

看效果:

3333.gif

代码实现如下:

findViewById(R.id.buttonPanel).setOnClickListener(v ->{
    placeholde_1.setContentId(-1);
    placeholde_2.setContentId(R.id.txt_2);
});


findViewById(R.id.buttonPane2).setOnClickListener(v ->{
    placeholde_2.setContentId(-1);
    placeholde_1.setContentId(R.id.txt_2);
});
复制代码

2.6.5、Layer

Layer什么效果呢。比如A B C在如图排布,想在想要有一个黑色背景包裹A,B,C,达到如图效果:

26.png

实现如下:

<androidx.constraintlayout.helper.widget.Layer
    android:id="@+id/layer"
    android:background="#000"
    app:constraint_referenced_ids="txt_a,txt_b,txt_c"
    android:padding="15dp"
    ...
    />


<TextView
    android:id="@+id/txt_a"
    ...
    />


<TextView
    android:id="@+id/txt_b"
    ...
    />


<TextView
    android:id="@+id/txt_c"
    ...
    />
复制代码

经过我实际测试,其实Layer能完全代替的了2.6.3的Group,但是不能实现Barrier的功能。

2.6.6、Flow

直接看图把,简单实现这种网格布局:

27.png

代码如下:

<androidx.constraintlayout.helper.widget.Flow
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:flow_verticalGap="10dp"
    app:flow_wrapMode="aligned"
    app:flow_maxElementsWrap="4"
    app:constraint_referenced_ids="txt_1,txt_2,txt_3,txt_4,txt_5,txt_6" />

<TextView
    android:id="@+id/txt_1"
    ...
    />

<TextView
    android:id="@+id/txt_2"
    ...
    />

<TextView
    android:id="@+id/txt_3"
    ...
    />

<TextView
    android:id="@+id/txt_4"
    ...
    />

<TextView
    android:id="@+id/txt_5"
    ...
    />

<TextView
    android:id="@+id/txt_6"
    ...
    />


<TextView
    android:id="@+id/txt_7"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:text="7"
    app:layout_constraintLeft_toLeftOf="@+id/txt_3"
    app:layout_constraintRight_toRightOf="@+id/txt_4"
    app:layout_constraintBottom_toBottomOf="@+id/txt_6"
    app:layout_constraintTop_toTopOf="@+id/txt_6"
    ...
    />
复制代码

没有约束就可以实现这种效果了。而且因为不是嵌套txt_7可以根据Flow里的元素进行约束实现自己想要的样式,这里就不过多介绍了,感兴趣的朋友可以自己去试试,介绍下属性把:

  • app:flow_wrapMode=“aligned” 有3个值。
alignednonechainchain2
绝对对齐(也就是网格对齐的方式)默认方式,会排成一排,屏幕宽度不够放时,2边出去和绝对对齐有点出入的是,比如6个元素,第一排4个,第二排是2个,这2个元素会平分横屏宽度和none类似,区别是,不够放时,会换行其他
  • app:flow_maxElementsWrap=“4” 一行几个元素
  • app:flow_verticalGap=“10dp” 竖直间距
  • app:flow_horizontalGap=“10dp” 横向间距
  • android:orientation=“horizontal” 水平方向的流式还是竖直方向的流式
  • app:flow_verticalAlign =“top” 值有top,bottom,center,baseline。每一行元素的对齐方式
  • app:flow_horizontalStyle = “ spread | spread_inside | packed ” 当wrapMode为chain或ALIGNED时生效
  • app:flow_horizontalBias = “ float " low的bias偏移,只在style为packed时生效

2.6.7、ImageFilterButton/ImageFilterView

功能很强大控件,包括圆角,图片滤镜等。 ImageFilterButton/ImageFilterView

三、代码动态修改约束及动画的实现。

比如把一个左上角的TextView,居中显示。代码如下:

ConstraintSet constraintSet = new ConstraintSet();
//克隆一个父布局约束,constraint就是当前父布局
constraintSet.clone(constraint);
//R.id.txt_1相对于父布局横向居中
constraintSet.centerHorizontally(R.id.txt_1,ConstraintSet.PARENT_ID);
//R.id.txt_1相对于父布局竖直居中
constraintSet.centerVertically(R.id.txt_1,ConstraintSet.PARENT_ID);
constraintSet.applyTo(constraint);
复制代码

再看下面的解释,可能更加清楚:

//意思R.id.view1的顶部和R.id.view2的顶部对齐
set.connect(R.id.view1, ConstraintSet.TOP, R.id.view2, ConstraintSet.TOP)

//上面就相当于XML布局里这句代码
//app:layout_constraintTop_toTop="@+id/view2"
复制代码

如果想要带动画效果去改变的话,我们只要在constraintSet.applyTo()前,加上这句代码,就会有动画效果:

TransitionManager.beginDelayedTransition(constraint);
复制代码

4443.gif


上面讲了一种可以代码改变,并且可以加动画效果的。接下来看,这种直接通过2个xml布局去添加约束,然后去改变。转变2个布局:

R.layout.constraint_activity_three 布局如下:

28.png

R.layout.constraint_activity_four 布局如下:

29.png

首先我们在activity里用的是R.layout.constraint_activity_three,点击按钮,让红色TextView A 和 蓝色按钮“点击改变”,通过动画变成R.layout.constraint_activity_four的样式。点击“恢复”后,又回到原来的样子。注意2个布局中,要改变约束的元素的id要保持一致,否则失效。我们看代码实现:

public class ConstraintLayoutSecondActivity extends AppCompatActivity {
    ConstraintLayout constraint;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.constraint_activity_three);
        constraint= findViewById(R.id.constraint);
        //改变
        findViewById(R.id.button_change).setOnClickListener(v ->{
            ConstraintSet constraintSet = new ConstraintSet();
            constraintSet.clone(ConstraintLayoutSecondActivity.this,R.layout.constraint_activity_four);
            TransitionManager.beginDelayedTransition(constraint);
            constraintSet.applyTo(constraint);
        });

        //恢复
        findViewById(R.id.button_reset).setOnClickListener(v->{
            ConstraintSet constraintSet = new ConstraintSet();
            constraintSet.clone(ConstraintLayoutSecondActivity.this,R.layout.constraint_activity_three);
            TransitionManager.beginDelayedTransition(constraint);
            constraintSet.applyTo(constraint);
        });
    }
}
复制代码

最终运行起来实现的效果如下:

4443.gif

小结

这篇文章,其实不难。主要是将 ConstraintLayout 的各种用法进行总结。如果觉得对你有所帮助的话,可以关注我徐公

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/184139.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解剖华为 Mate 50 Pro主板

华为Mate 50 Pro整体拆解难度中等&#xff0c;可还原性强。主板则是采用堆叠结构&#xff0c;主板1正面主要IC包括高通骁龙84G处理器芯片…… 日前&#xff0c;有拆解机构对华为Mate 50 Pro整机进行了拆解&#xff0c;表示其内部的配件大约有90%是国产元器件&#xff0c;如屏幕…

【Node.js实战】一文带你开发博客项目之Express重构(初始化环境,处理 session,连接 redis)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;秋招&#xff09; &#x1f680;未…

循环UI列表

先看一下效果 支持自定义选项数量,按钮切换,鼠标滑动切换,当前项框选提示,选项缩放等功能 SlideSwitch&#xff1a;鼠标切换选项开关,关闭只能点击按钮切换 SlideOffset&#xff1a;滑动触发值,鼠标X轴向滑动大于此值切换选项,小于不触发 ScaleSwitch&#xff1a;缩放开关,开启…

乘法逆元 +数论分块 +平方和公式

年后准备学习啦&#xff0c;开学还得准备考试。 乘法逆元&#xff1a; 因为涉及到除法&#xff0c;所以取余这个操作就错误。 所以如果我们要求&#xff08;a/b)%mod&#xff0c;我们可以假设 (a/b)%mod a*c%mod 那么c就是b的逆元。 怎么求逆元呢&#xff0c;其实有很多方法…

指定加拿大UBC|临床肿瘤专业应届博士成功获访问学者offer

G博士指定加拿大UBC&#xff0c;本人具有多年的临床工作经验&#xff0c;但科研产出较少。经过努力&#xff0c;最终我们落实了该校的访问学者职位。又历经半年的流程&#xff0c;G博士终于获得加拿大签证&#xff0c;前往UBC报到。建议&#xff1a;提前申请&#xff0c;预留出…

蓝桥杯刷题-入门题(终章一)

你是如风的少年~&#x1f603; 空 清新民谣版 - 汪小敏 - 单曲 - 网易云音乐 自在的少年 - 要不要买菜 - 单曲 - 网易云音乐 最后15道入门题&#xff0c;做完这15道&#xff0c;NEWOJ就91道题AC了 目录 一&#xff0c;数根 二&#xff0c;最大值和最小值&#xff08;I&…

Qt扫盲-QTime理论总结

QTime理论总结一、概述二、使用1. 属性获取2. 时间加减3. 字符串与QTime互转一、概述 QTime对象包含一个时钟时间&#xff0c;可以用小时数、分钟数、秒数和毫秒数来表示。它提供了比较时间和通过添加毫秒数来操作时间的函数。 QTime使用24小时时钟格式&#xff1b;它没有AM/…

bigemap如何设置等高线坐标系并输出

如何设置等高线坐标系并输出发布时间&#xff1a;2018-01-17 版权&#xff1a;投影设置及数据导出矢量等高线生成完成后&#xff08;详细生成过程参加上一章节&#xff1a;矢量等高线生成&#xff09;,我们就能够设置投影和导出等高线数据。投影设置我们生成等高线默认的坐标是…

大数据集群环境搭建

文章目录本文要点内容大纲一、大数据集群环境搭建1.1、分布式、集群概念初识1.2、集群环境搭建1.2.1、虚拟机克隆1.2.2、修改IP、主机名1.2.3、主机名和IP映射配置1.2.4、防火墙关闭1.2.5、集群机器间免密登录1.2.6、跨机器远程copy文件1.2.7、集群的时间同步问题二、Centos软件…

【3】Linux权限管控

学习笔记目录 初识Linux--入门Linux基础命令--会用Linux权限管控--懂权限Linux实用操作--熟练实战软件部署--深入掌握脚本&自动化--用的更强项目实战--学到经验云平台技术--紧跟潮流 认知root用户 root用户&#xff08;超级管理员&#xff09; 无论是Windows、MacOS、L…

【iMessage苹果家庭推推送源码】掀开应用程序“终端”,输入CDDESKTOP运转指令证书

推荐内容IMESSGAE相关 作者✈️IMEAX推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容3.日历推 *** …

沁恒CH32V307单片机入门(01):基础说明与流程体验

文章目录目的基础说明芯片介绍资料与工具开发环境流程体验开发调试下载总结目的 工作这几年单片机主要就接触过 Atmel、Renesas、Microchip、ST 这些厂家的&#xff0c;最近几年因为内部外部的各种因素单片机的价格和供应都挺不稳定的&#xff0c;将来会发生什么也不好说。另外…

python jenkins使用方法/使用笔记

笔者也经常在网上查询信息,但发现很多信息都是照搬,内容甚至有错误,可用性很低.笔者就认为如果要分享就应该把遇到的问题真实的分享出来,让更多同路人少走弯路.节约时间.觉得这篇文章有帮助的同学可以点个赞!将真有用的信息传递给更多人!常用的方法安装 jenkins 依赖pip instal…

python+django校园失物招领系统_13i29.

用户注册&#xff1a;用户填写用户名、密码、年级、姓名、电话号码、邮箱 &#xff0c;然后点击注册按钮进行注册。 用户登录&#xff1a;用户填写已经注册的用户名和密码并输入验证码&#xff0c;点击登录按钮进行登录。 搜索&#xff1a;用户可以在搜索栏输入关键字进行检索&…

京阳科技拟在上交所上市:计划募资12亿元,业绩波动较大

近日&#xff0c;山东京阳科技股份有限公司&#xff08;下称“京阳科技”&#xff09;预披露招股书&#xff0c;准备在上海证券交易所主板上市。本次冲刺上市&#xff0c;京阳科技计划募资12亿元&#xff0c;用于10万吨/年新能源锂电池材料前驱体项目。 据招股书介绍&#xff0…

【刷题】珠玑妙算

至此&#xff0c;我终于明白了哈希表真正的妙用。 目录 文章目录 前言 一、珠玑妙算 二、具体实现 1.哈希表的构建 2.总结规律 1&#xff09;给出两个字符串&#xff1a;"YBBY"&#xff0c;"GYYB"&#xff0c;构建哈希表&#xff1a;&#xff08;少猜了一个…

ch2 计算机的发展史

1. 计算机的发展史 人类活动的需求&#xff0c; 推动因素&#xff1a; 电子技术的发展计算机体系结构技术的发展 1. 1 计算机的体系结构 冯诺依曼 体系结构的计算机&#xff1b; 以运算器为核心的 冯诺依曼结构&#xff1b; IBM 360 &#xff1a; 提出计算机系统结构的概念…

DeepTime:时间序列预测中的元学习模型

DeepTime&#xff0c;是一个结合使用元学习的深度时间指数模型。通过使用元学习公式来预测未来&#xff0c;以应对时间序列中的常见问题&#xff08;协变量偏移和条件分布偏移——非平稳&#xff09;。该模型是时间序列预测的元学习公式协同作用的一个很好的例子。 DeepTime架…

Win系统速览桌面功能失效 - 解决方案

Win系统速览桌面功能失效 - 解决方案问题解决方案步骤1&#xff1a;确保显卡驱动正常运行步骤2&#xff1a;检查任务栏设置步骤3&#xff1a;调整视觉效果问题 Win10系统支持用户鼠标悬停在任务栏右下角时速览桌面。但可能会因驱动和视觉效果设置等原因导致此功能失效。甚至任…

Linux基础IO+文件fd

1&#xff1a;文件理解文件内容属性&#xff0c;因此空文件在磁盘上也占用空间。文件用路径名文件名作为标识文件的唯一性。对文件的操作&#xff0c;就是对文件的内容属性的操作。在linux中&#xff0c;如果没有指定文件路径&#xff0c;默认在当前路径下执行操作。总结&#…