如何使用ConstraintLayout代替三大控件

相信大家都听说过ConstrainLayout 布局,它是现在Google 推荐的布局,用来减少布局的层级。虽然网上有很多的教程,但是很多人仍然喜欢使用LinearLayout、FrameLayout等布局。

对于这种情况,我认为主要的原因是,Constrainlayout的属性和功能太多了。比如当我们需要实现一些在LinearLayout等布局中很简单的效果时,大部分因为网上Constrainlayout的教程内容太多了而劝退,最后还是用的其他布局。

这篇文章将直接介绍如何使用Constrainlayout 来代替其他控件,要让你先用起来,然后才能慢慢熟悉它。好了,废话不多说,我们直接开始吧。

代替FrameLayout

FrameLayout 是一个简单的父控件,我们一般使用layout_gravity来定位子控件的位置。如下图所示,假设我们需要在图片的右上角显示红点:

使用FrameLayout的代码如下,这里就不多介绍了。

ini 复制代码
<FrameLayout
        android:layout_width="120dp"
        android:layout_height="120dp">
        <androidx.constraintlayout.utils.widget.ImageFilterView
            android:layout_gravity="center"
            android:src="@drawable/blur_test"
            android:scaleType="centerCrop"
            android:layout_width="100dp"
            android:layout_height="100dp"/>
        <ImageView
            android:layout_gravity="end|top"
            android:src="@drawable/red_pot"
            android:layout_width="20dp"
            android:layout_height="20dp"/>
</FrameLayout>

如果我们使用ConstrainLayout 布局,它有两种方式实现:

  1. 使用约束实现,代码如下
ini 复制代码
<androidx.constraintlayout.widget.ConstraintLayout         xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.constraintlayout.utils.widget.ImageFilterView
        android:id="@+id/icon"
        android:scaleType="centerCrop"
        android:src="@drawable/blur_test"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_width="100dp"
        android:layout_height="100dp"/>
    <ImageView
        android:layout_width="20dp"
        android:layout_height="20dp"
        //下面4行是关键代码
        app:layout_constraintStart_toEndOf="@id/icon"
        app:layout_constraintEnd_toEndOf="@id/icon"
        app:layout_constraintTop_toTopOf="@id/icon"
        app:layout_constraintBottom_toTopOf="@id/icon"
        android:src="@drawable/red_pot" />    
</androidx.constraintlayout.widget.ConstraintLayout>

效果如下图,可以看到使用ConstrainLayout 布局的约束可以方便地实现。只需要让红点控件的satrt、end约束依赖图片的end边;top、bottom约束图片的top边就可以了。

不过这种方式有个缺陷:你设置的margin 会没有效果。如果你要为圆形头像加红点,如下图所示,这个时候就会有问题。

这种情况下,我们可以使用 Space 控件来解决,不过我更推荐使用下面的第二种方式。关于Space 控件具体可以看如何在 ConstraintLayout 中设置负值的 Margin

  1. 使用圆形定位实现,代码如下
ini 复制代码
<ImageView
    android:layout_width="20dp"
    android:layout_height="20dp"
    app:layout_constraintCircle="@id/icon" //以哪个控件为圆心
    app:layout_constraintCircleAngle="45"  //角度
    app:layout_constraintCircleRadius="50dp" //半径
    android:src="@drawable/red_pot" />

可以看到使用圆形定位非常简单,只需要设置图片控件为圆心,偏移角度45度,以及半径就可以简单地实现下图的红点效果了。

代替LinearLayout

● 代替layout_weight

在LinearLayout中,我们使用layout_weight来设置当前 View 的占比权重。在ConstrainLayout中,我们可以使用layout_constraintHorizontal_weight (水平方向上)来代替它。代码如下,我们以 1:2:3 的比例来显示子View。

ini 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">


   <ImageView
       android:id="@+id/bg"
       android:background="@color/white"
       app:layout_constraintTop_toTopOf="parent"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       android:layout_width="100dp"
       android:layout_height="50dp"/>

    <ImageView
        android:id="@+id/view1"
        android:src="@color/black"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toStartOf="@id/bg"
        app:layout_constraintEnd_toStartOf="@id/view2"
        app:layout_constraintTop_toTopOf="@id/bg"
        app:layout_constraintBottom_toBottomOf="@id/bg"
        android:layout_width="0dp"
        android:layout_height="20dp"/>

    <ImageView
        android:id="@+id/view2"
        android:src="@color/teal_200"
        app:layout_constraintHorizontal_weight="2"
        app:layout_constraintStart_toEndOf="@id/view1"
        app:layout_constraintEnd_toEndOf="@id/view3"
        app:layout_constraintTop_toTopOf="@id/bg"
        app:layout_constraintBottom_toBottomOf="@id/bg"
        android:layout_width="0dp"
        android:layout_height="20dp"/>

    <ImageView
        android:id="@+id/view3"
        android:src="@color/teal_700"
        app:layout_constraintHorizontal_weight="3"
        app:layout_constraintStart_toEndOf="@id/view2"
        app:layout_constraintEnd_toEndOf="@id/bg"
        app:layout_constraintTop_toTopOf="@id/bg"
        app:layout_constraintBottom_toBottomOf="@id/bg"
        android:layout_width="0dp"
        android:layout_height="20dp"/>
   </androidx.constraintlayout.widget.ConstraintLayout>

效果如下图。

● 代替gravity 整体居中

上图是我们常见的关注按钮,需要让ImageView和 TextView一起在父布局中整体居中。在LinearLayout中实现非常简单,代码如下:

ini 复制代码
<LinearLayout
        android:gravity="center" //只需要这一行就可以了
        android:orientation="horizontal"
        android:background="@color/white"
        android:layout_width="100dp"
        android:layout_height="50dp">
        <ImageView
            android:src="@mipmap/add"
            android:layout_gravity="center"
            android:layout_width="20dp"
            android:layout_height="20dp"/>
        <TextView
            android:textColor="@color/black"
            android:text="关注"
            android:gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="20dp"/>
    </LinearLayout>

而在ConstraintLayout中有两种方式实现类似的效果

● 使用约束

ini 复制代码
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

   <ImageView
       android:id="@+id/bg"
       android:background="@color/white"
       app:layout_constraintTop_toTopOf="parent"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       android:layout_width="100dp"
       android:layout_height="50dp"/>

    <ImageView
        android:id="@+id/view1"
        android:src="@mipmap/add"
        //关键代码,设置约束链的样式。
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="@id/bg"
        app:layout_constraintEnd_toStartOf="@id/view2"
        app:layout_constraintTop_toTopOf="@id/bg"
        app:layout_constraintBottom_toBottomOf="@id/bg"
        android:layout_width="20dp"
        android:layout_height="20dp"/>

    <TextView
        android:textColor="@color/black"
        android:text="关注"
        android:id="@+id/view2"
        app:layout_constraintStart_toEndOf="@id/view1"
        app:layout_constraintEnd_toEndOf="@id/bg"
        app:layout_constraintTop_toTopOf="@id/bg"
        app:layout_constraintBottom_toBottomOf="@id/bg"
        android:layout_width="wrap_content"
        android:layout_height="20dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

在上面的代码中,我们使用了layout_constraintHorizontal_chainStyle属性来实现整体居中的效果。该属性是设置约束链的样式,它有三种,其效果如下

  1. Spread:在考虑外边距后,视图会均匀分布。这是默认值。

  2. Spread Inside:第一个视图和最后一个视图固定在链两端的约束条件上,其余视图均匀分布。

  3. Packed:在考虑外边距之后,视图将打包在一起。

Spread(默认) Spread inside packed

● 使用Flow

当子View太多时,我们一个一个来互相约束就太麻烦。这时我们可以使用Flow,代码如下

ini 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.constraintlayout.helper.widget.Flow
        app:layout_constraintStart_toStartOf="@id/bg"
        app:layout_constraintEnd_toEndOf="@id/bg"
        app:layout_constraintTop_toTopOf="@id/bg"
        app:layout_constraintBottom_toBottomOf="@id/bg"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        //可以看到我们只需要设置Flow的依赖就可以了
        app:flow_firstHorizontalStyle="packed"
        app:constraint_referenced_ids="view1,view2"
        />

    <ImageView
        android:id="@+id/bg"
        android:background="@color/white"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_width="100dp"
        android:layout_height="50dp"/>

    <ImageView
        android:id="@+id/view1"
        android:src="@mipmap/add"
        android:layout_width="20dp"
        android:layout_height="20dp"/>

    <TextView
        android:textColor="@color/black"
        android:text="关注"
        android:id="@+id/view2"
        android:layout_width="wrap_content"
        android:layout_height="20dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

代替RelativeLayout

ConstraintLayout替代RelativeLayout的功能太多了,这里就介绍一个ConstraintLayout独特的文字基线对齐layout_constraintBaseline_toBaselineOf 属性,它表示以baseline对齐,而不是View的底部对齐。

ini 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    
    <TextView
        android:textColor="@color/white"
        android:text="你好"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:background="@color/teal_700"
        android:id="@+id/view1"
        android:gravity="center"
        android:layout_width="40dp"
        android:layout_height="40dp"/>

    <TextView
        android:textColor="@color/white"
        android:text="世界"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toEndOf="@id/view1"
        app:layout_constraintBaseline_toBaselineOf="@id/view1"
        app:layout_constraintEnd_toEndOf="parent"
        android:gravity="center"
        app:layout_constraintHorizontal_bias="0"
        android:background="@color/teal_200"
        android:id="@+id/view2"
        android:layout_width="50dp"
        android:layout_height="50dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

效果如下图

总结

这篇文章介绍了如何使用ConstraintLayout 代替三个常用的布局。不过这不算结束,ConstraintLayout 还有很多功能没有介绍,下一篇文章将介绍ConstraintLayout 的其他属性。文章最后求一个免费的赞吧🥺🥺

参考

www.jianshu.com/p/568e3c22e...

www.jianshu.com/p/28bc3619f...

相关推荐
千里马学框架2 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone2 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc2 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui