一年前写ConstraintLayout,看完一篇真的就够了么? 文章的时候说过,任何技术都会有时限性,只有不断的学习,不断的更新自我,才不会outer。 有朋友也留言,但愿更新...那就有本文了。android
目前2.0只是新增了一些新功能和新玩法,对1.x版本无取代之意,因此1.x版本仍是得学习的。好文推荐 2.0版本新增的内容在实践开发也是很是实用的,建议能够上车了。git
「因为无知与惰性,让咱们感受摸到了技术的天花板」github
「对你有用,帮忙点赞~」api
基于本文发表,ConstraintLayout版本已经更新到2.0.0-beta8
,因此添加依赖的姿式:markdown
AndroidX:
app
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta8' 复制代码
支持库:ide
implementation 'com.android.support.constraint:constraint-layout:2.0.0-beta8' 复制代码
版本说明:oop
alpha
:内部测试版,bug多多;布局
beta
:公开测试版本,bug少点,支持尝鲜;post
rc
:候选版本,功能不增,和发布版本一致,修修小bug;
stable
:稳定版本,你尽管用,bug能找到是福气。
正常状况下,列表显示通常采用ListView或者RecyclerView来实现,但其子Item布局是很是呆板的。想象一下,若是一部做品的详情页结束打上一堆标签,样式以下,该怎么实现?
这种布局采用
Flow
来实现特别的简单和方便,并且经过flow_wrapMode
属性能够设置不一样对齐方式。
下面布局代码简单示例:Flow
布局经过constraint_referenced_ids
属性将要约束的View
的id
进行关联,这里简单关联A
到G
的TextView
,因为TextView
没有设置约束条件,因此Android Studio 4.0 会报红,给ConstraintLayout
布局添加tools:ignore="MissingConstraints"
忽略报红提示。
Flow
布局的flow_horizontalGap
属性表示水平之间两个View的水平间隔,flow_verticalGap
则是垂直方向间隔。
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:ignore="MissingConstraints"//忽略Android Studio 4.0报红提示 tools:context=".MainActivity"> <androidx.constraintlayout.helper.widget.Flow android:id="@+id/flow" android:layout_width="wrap_content" android:layout_height="wrap_content" app:constraint_referenced_ids="tvA,tvB,tvC,tvD,tvE,tvF,tvG" app:flow_horizontalGap="30dp" //View水平间隔 app:flow_verticalGap="30dp" //垂直间隔 app:flow_wrapMode="none" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tvA" android:layout_width="50dp" android:layout_height="50dp" android:background="@color/colorPrimary" android:gravity="center" android:text="A" android:textColor="#ffffff" android:textSize="16sp" /> <TextView android:id="@+id/tvB" android:layout_width="50dp" android:layout_height="50dp" android:background="@color/colorPrimary" android:gravity="center" android:text="B" android:textColor="#ffffff" android:textSize="16sp" /> <TextView android:id="@+id/tvC" android:layout_width="50dp" android:layout_height="50dp" android:background="@color/colorPrimary" android:gravity="center" android:text="C" android:textColor="#ffffff" android:textSize="16sp" /> <TextView android:id="@+id/tvD" android:layout_width="50dp" android:layout_height="50dp" android:background="@color/colorPrimary" android:gravity="center" android:text="D" android:textColor="#ffffff" android:textSize="16sp" /> <TextView android:id="@+id/tvE" android:layout_width="50dp" android:layout_height="50dp" android:background="@color/colorPrimary" android:gravity="center" android:text="E" android:textColor="#ffffff" android:textSize="16sp" /> <TextView android:id="@+id/tvF" android:layout_width="50dp" android:layout_height="50dp" android:background="@color/colorPrimary" android:gravity="center" android:text="F" android:textColor="#ffffff" android:textSize="16sp" /> <TextView android:id="@+id/tvG" android:layout_width="50dp" android:layout_height="50dp" android:background="@color/colorPrimary" android:gravity="center" android:text="G" android:textColor="#ffffff" android:textSize="16sp" /> </androidx.constraintlayout.widget.ConstraintLayout> 复制代码
flow_wrapMode
属性一共有三种值,在上面的布局的基础上,更换一下不一样的值,看一下效果:
「none值」:全部引用的View造成一条链,水平居中,超出屏幕两侧的View
不可见。
「chian值」:所引用的View
造成一条链,超出部分会自动换行,同行的View
会平分宽度。
「aligned值」:所引用的View
造成一条链,但View
会在同行同列。
即然是一条链,那么能够经过链的样式进行约束。
当flow_wrapMode
属性为aligned
和chian
属性时,经过链进行约束。ConstraintLayout,看完一篇真的就够了么? 此文有谈到链约束(Chain
)。
给Flow
布局添加如下属性进行不一样chain
约束:
flow_firstHorizontalStyle
约束第一条水平链,当有多条链(多行)时,只约束第一条链(第一行),其余链(其余行)不约束;flow_lastHorizontalStyle
约束最后一条水平链,当有多条链(多行)时,只约束最后一条链(最后一行),其余链(其余行)不约束;flow_horizontalStyle
约束全部水平链;flow_firstVerticalStyle
同水平约束;flow_lastVerticalStyle
同水平约束;flow_verticalStyle
约束全部垂直链;以上属性,取值有:spread
、spread_inside
、packed
「效果:」
「spread值:
」
代码:
<androidx.constraintlayout.helper.widget.Flow android:id="@+id/flow" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" app:constraint_referenced_ids="tvA,tvB,tvC,tvD,tvE,tvF,tvG" app:flow_maxElementsWrap="4" app:flow_horizontalGap="30dp" app:flow_verticalGap="30dp" app:flow_wrapMode="chain" app:flow_horizontalStyle="spread" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> 复制代码
「spread_inside值:
」
代码:
<androidx.constraintlayout.helper.widget.Flow android:id="@+id/flow" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" app:constraint_referenced_ids="tvA,tvB,tvC,tvD,tvE,tvF,tvG" app:flow_maxElementsWrap="4" app:flow_horizontalGap="30dp" app:flow_verticalGap="30dp" app:flow_wrapMode="chain" app:flow_horizontalStyle="spread_inside" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> 复制代码
「packed值:
」
代码:
<androidx.constraintlayout.helper.widget.Flow android:id="@+id/flow" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" app:constraint_referenced_ids="tvA,tvB,tvC,tvD,tvE,tvF,tvG" app:flow_maxElementsWrap="4" app:flow_horizontalGap="30dp" app:flow_verticalGap="30dp" app:flow_wrapMode="chain" app:flow_horizontalStyle="packed" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> 复制代码
其余效果你们在实践能够尝试看看效果,建议「点赞」收藏本文,在使用不会能够翻阅一下,效率事半功倍,省得从新浪费时间谷歌搜索。
上文XML布局中,全部TextView的宽高是一致的,因此看着整整齐齐,当宽高不一致时,能够进行对齐处理。我的试了一下app:flow_wrapMode="aligned"
下的对齐,没啥效果,估计有默认值了吧。看看flow_wrapMode
属性为none
和chain
状况吧。
给Flow
布局添加如下属性进行不一样Align
约束:
flow_verticalAlign
垂直方向对齐,取值有:top
、bottom
、center
、baseline
;flow_horizontalAlign
水平方向对齐,取值有:start
、end
、center
;对齐方向通常与链的方向相反才可生效,例如垂直链样式,通常对齐View
的左右边和中间。
简单举个例子:垂直方向顶部对齐。
「效果图:」
能够看到
E
和G
、F
顶部对齐。
代码:
<androidx.constraintlayout.helper.widget.Flow android:id="@+id/flow" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" app:constraint_referenced_ids="tvA,tvB,tvC,tvD,tvE,tvF,tvG" app:flow_maxElementsWrap="4" app:flow_horizontalGap="30dp" app:flow_verticalGap="30dp" app:flow_wrapMode="chain" app:flow_verticalAlign="top" app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> 复制代码
简单的理解aligned
和chian
是none
的定制版,经过添加不一样的属性定制而成。因为Flow
是虚拟布局,简单理解就是约束助手,它并不会增长布局层级,却能够像正常的布局同样使用。
「其余属性」
上文的XML的布局没有设置Flow对View的组织方式(水平or 垂直),能够经过orientation
属性来设置水平horizontal
和垂直vertical
方向,例如改成垂直方向。
当flow_wrapMode
属性为aligned
和chian
时,经过flow_maxElementsWrap
属性控制每行最大的子View
数量。例如:flow_maxElementsWrap=3
。
当flow_wrapMode
属性为none
时,A和G被挡住了,看不到。
要A或者G可见,经过设置
flow_horizontalBias
属性,取值在0-1
之间。前提条件是flow_horizontalStyle
属性为packed
才会生效。
<androidx.constraintlayout.helper.widget.Flow android:id="@+id/flow" android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" app:constraint_referenced_ids="tvA,tvB,tvC,tvD,tvE,tvF,tvG" app:flow_horizontalGap="30dp" app:flow_verticalGap="30dp" app:flow_wrapMode="none" app:flow_horizontalStyle="packed" app:flow_horizontalBias="0" android:layout_marginTop="10dp" app:layout_constraintRight_toRightOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> 复制代码
「效果图:」 设置
flow_horizontalBias=1
那么G就能够看到了。该属性还有其余相似ChainStyle的属性w玩法,具体能够实践体验。固然,也能够在flow_wrapMode
属性为其余值生效。
经过不一样的属性能够搭配不少不一样的效果,再加上MotionLayout动画,那就更炫酷了。
Layer也是一个约束助手ConstraintHelper
,相对Flow比较简单,经常使用来增长背景,或者共同动画。因为ConstraintHelper
自己继承自View
,跟咱们本身经过View在ConstraintLayout
布局中给多个View添加共同背景没什么区别,只是更方便而已。
「一、添加背景」
给ImageView
和TextView
添加个共同背景:
「效果:」
「代码:」
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.constraintlayout.helper.widget.Layer android:id="@+id/layer" android:layout_marginTop="50dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/colorPrimary" app:constraint_referenced_ids="ivImage,tvName" app:layout_constraintLeft_toLeftOf="@id/ivImage" app:layout_constraintRight_toRightOf="parent" android:padding="10dp" app:layout_constraintTop_toTopOf="parent" tools:ignore="MissingConstraints" /> <ImageView android:id="@+id/ivImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:src="@mipmap/ic_launcher_round" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/layer" /> <TextView android:id="@+id/tvName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新小梦" android:textColor="#FFFFFF" android:paddingTop="5dp" app:layout_constraintLeft_toLeftOf="@id/ivImage" app:layout_constraintRight_toRightOf="@id/ivImage" app:layout_constraintTop_toBottomOf="@id/ivImage" /> </androidx.constraintlayout.widget.ConstraintLayout> 复制代码
「二、共同动画」
经过属性动画给ImageView和TextView添加经过动画效果。
「效果:」
「代码:」
val animator = ValueAnimator.ofFloat( 0f, 360f) animator.repeatMode=ValueAnimator.RESTART animator.duration=2000 animator.interpolator=LinearInterpolator() animator.repeatCount=ValueAnimator.INFINITE animator.addUpdateListener { layer.rotation= it.animatedValue as Float } layer.setOnClickListener { animator.start() } 复制代码
对属性动画模糊的同窗能够看看:Android属性动画,看完这篇够用了吧
支持:旋转、位移、缩放动画。透明效果试了一下,是针对自身的,而不是约束的View。
Flow
和Layer
都是ConstraintHelper
的子类,当二者不知足需求时,能够经过继承ConstraintHelper
来实现想要的约束效果。
在某乎APP有这么个相似的动画广告:
那么经过自定义ConstraintHelper来实现就很是简单:
class AdHelper : ConstraintHelper { constructor(context: Context?) : super(context) constructor(context: Context?,attributeSet: AttributeSet):super(context,attributeSet) constructor(context: Context?,attributeSet: AttributeSet,defStyleAttr: Int):super(context,attributeSet,defStyleAttr) override fun updatePostLayout(container: ConstraintLayout?) { super.updatePostLayout(container) val views = getViews(container) views.forEach { val anim = ViewAnimationUtils.createCircularReveal(it, 0, 0, 0f, it.width.toFloat()) anim.duration = 5000 anim.start() } } } 复制代码
布局引用AdHleper
:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.constraint.AdHelper android:layout_width="wrap_content" android:layout_height="wrap_content" app:constraint_referenced_ids="ivLogo" app:layout_constraintLeft_toLeftOf="@id/ivLogo" app:layout_constraintRight_toRightOf="@id/ivLogo" app:layout_constraintTop_toTopOf="@id/ivLogo" /> <ImageView android:id="@+id/ivLogo" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:adjustViewBounds="true" android:scaleType="fitXY" android:src="@mipmap/ic_logo" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> 复制代码
圆角图片,圆形图片怎么实现?自定义View?经过ImageFilterButton
,一个属性就搞定;ImageFilterButto
能作的还有更多。
看看如何实现圆角或圆形图片:
「原图:」
将
roundPercent
属性设置为1
,取值在0-1
,由正方形向圆形过渡。
<androidx.constraintlayout.utils.widget.ImageFilterButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="100dp" app:roundPercent="1" android:src="@mipmap/ic_launcher" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> 复制代码
「效果:」
也能够经过设置
round
属性来实现:
<androidx.constraintlayout.utils.widget.ImageFilterButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="100dp" android:src="@mipmap/ic_launcher" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:round="50dp" /> 复制代码
「其余属性:」
altSrc
和src
属性是同样的概念,altSrc
提供的资源将会和src
提供的资源经过crossfade
属性造成交叉淡化效果。默认状况下,crossfade=0
,altSrc
所引用的资源不可见,取值在0-1
。 例如:
<androidx.constraintlayout.utils.widget.ImageFilterButton android:id="@+id/ivImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="100dp" android:src="@mipmap/ic_launcher" app:altSrc="@mipmap/ic_sun" app:crossfade="0.5" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:round="50dp" /> 复制代码
crossfade=0.5时,效果:
crossfade=1时,效果:
接下来几个属性是对图片进行调节:
warmth
色温:1=neutral天然, 2=warm暖色, 0.5=cold冷色
brightness
亮度:0 = black暗色, 1 = original原始, 2 = twice as bright两倍亮度
;这个效果很差贴图,你们自行验证;
saturation
饱和度:0 = grayscale灰色, 1 = original原始, 2 = hyper saturated超饱和
;
contrast
对比:1 = unchanged原始, 0 = gray暗淡, 2 = high contrast高对比
;
上面属性的取值都是0、一、2,不过你们能够取其余值,效果也是不同的。 最后一个属性overlay
,表示不知道怎么用,看不到没效果,你们看看评论跟我说声?
ImageFilterView
与ImageFilterButton
的属性如出一辙,只是它两继承的父类不同,一些操做也就不同。ImageFilterButton
继承自AppCompatImageButton
,也就是ImageButtion
。而ImageFilterView
继承自ImageView
。
还记得你家项目经理给你的UI原型图么?想不想回敬一下项目经理,是时候了~
MockView
能简单的帮助构建UI界面,经过对角线造成的矩形+标签。例如:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.constraintlayout.utils.widget.MockView android:id="@+id/first" android:layout_width="100dp" android:layout_height="100dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.constraintlayout.utils.widget.MockView android:id="@+id/second" android:layout_width="100dp" android:layout_height="100dp" app:layout_constraintLeft_toRightOf="@id/first" app:layout_constraintTop_toBottomOf="@id/first" /> </androidx.constraintlayout.widget.ConstraintLayout> 复制代码
「效果:」
中间黑色显示的是
MockView
的id
。经过MockView
能够很好的构建一些UI思路。
MitionLayou主要是用来实现动做动画,能够参考个人另外一篇文章:Android MotionLayout动画:续写ConstraintLayout新篇章
有ConstraintLayout
实践经验的朋友应该知道margin
设置负值在ConstraintLayout
是没有效果的。例以下面布局:TextView B的layout_marginLeft
和layout_marginTop
属性是不会生效的。
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/vA" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginLeft="30dp" android:layout_marginTop="30dp" android:background="@color/colorPrimary" android:gravity="center" android:text="A" android:textColor="#FFFFFF" android:textSize="20sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/vB" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginLeft="-30dp" android:layout_marginTop="-30dp" android:background="@color/colorAccent" android:gravity="center" android:text="B" android:textColor="#FFFFFF" android:textSize="20sp" app:layout_constraintLeft_toRightOf="@id/vA" app:layout_constraintTop_toBottomOf="@id/vA" /> </androidx.constraintlayout.widget.ConstraintLayout> 复制代码
「效果:」 能够经过轻量级的
Space
来间接实现这种效果。
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/vA" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginLeft="30dp" android:layout_marginTop="30dp" android:background="@color/colorPrimary" android:gravity="center" android:text="A" android:textColor="#FFFFFF" android:textSize="20sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Space android:id="@+id/space" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginRight="30dp" android:layout_marginBottom="30dp" app:layout_constraintBottom_toBottomOf="@id/vA" app:layout_constraintRight_toRightOf="@id/vA" /> <TextView android:id="@+id/vB" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginLeft="-30dp" android:layout_marginTop="-30dp" android:background="@color/colorAccent" android:gravity="center" android:text="B" android:textColor="#FFFFFF" android:textSize="20sp" app:layout_constraintLeft_toRightOf="@id/space" app:layout_constraintTop_toBottomOf="@id/space" /> </androidx.constraintlayout.widget.ConstraintLayout> 复制代码
「效果:」
2.0还增长了ConstraintProperties
类用于经过api(代码)更新ConstraintLayout
子视图;其余一些能够参考官方文档,估计也差很少了。
「参考:」
能读到末尾的小伙伴都是很棒,耐力很好。若是本文对你有用,帮忙「点个赞」,推荐好文。
最后的最后,我的能力有限,有理解错误或者错误的地方,但愿你们帮忙纠正,很是感谢。
「欢迎star 欢迎点赞」:Github
本文使用 mdnice 排版