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

相关推荐
幻雨様3 小时前
UE5多人MOBA+GAS 45、制作冲刺技能
android·ue5
Jerry说前后端4 小时前
Android 数据可视化开发:从技术选型到性能优化
android·信息可视化·性能优化
Meteors.5 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton6 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw10 小时前
安卓图片性能优化技巧
android
风往哪边走10 小时前
自定义底部筛选弹框
android
Yyyy48211 小时前
MyCAT基础概念
android
Android轮子哥11 小时前
尝试解决 Android 适配最后一公里
android
雨白12 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android
风往哪边走13 小时前
自定义仿日历组件弹框
android