如何使用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...

相关推荐
L7256几秒前
Android的Handler
android
清风徐来辽几秒前
Android HandlerThread 基础
android
HerayChen1 小时前
HbuildderX运行到手机或模拟器的Android App基座识别不到设备 mac
android·macos·智能手机
顾北川_野1 小时前
Android 手机设备的OEM-unlock解锁 和 adb push文件
android·java
hairenjing11231 小时前
在 Android 手机上从SD 卡恢复数据的 6 个有效应用程序
android·人工智能·windows·macos·智能手机
小黄人软件2 小时前
android浏览器源码 可输入地址或关键词搜索 android studio 2024 可开发可改地址
android·ide·android studio
dj15402252032 小时前
group_concat配置影响程序出bug
android·bug
周全全2 小时前
MySQL报错解决:The user specified as a definer (‘root‘@‘%‘) does not exist
android·数据库·mysql
- 羊羊不超越 -3 小时前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos