相信大家都听说过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 布局,它有两种方式实现:
- 使用约束实现,代码如下
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 。
- 使用圆形定位实现,代码如下
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属性来实现整体居中的效果。该属性是设置约束链的样式,它有三种,其效果如下
-
Spread:在考虑外边距后,视图会均匀分布。这是默认值。
-
Spread Inside:第一个视图和最后一个视图固定在链两端的约束条件上,其余视图均匀分布。
-
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 的其他属性。文章最后求一个免费的赞吧🥺🥺