2020.06.28更新: Flow使用详解android
约束布局2.0未使用过约束布局的,可先查看上一篇文章ConstraintLayout 约束布局1.xgit
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3'
github
约束布局是一个容许你灵活定义view
位置和大小的ViewGroup
,具备多种辅助工具,如GuideLine、Barrier、Group等。在灵活地放置各类各样的view时,并不会增长Layout层级。2.0版本出了优化布局性能外,还增长了一些新特性,使得开发过程更加方便:app
开发实际发现,到如今居然还有些人看不上约束布局,Google对于约束布局的信心和野心,难道还不足以引发重视?? ide
Layer功能上能够理解为包含它所引用的view的一个父布局viewGroup,但并不会增长layout的层级。这点是很是好用的,在Layer以前,想往本身view统一加个背景限制,通常都是另外加个view来作纯背景展现。工具
像开发过程当中这种带图标的dialog,能够用layer方便圈出背景。 布局
另外,Layer支持对里面的 view 一块儿作变换,可看待成一个日常的父布局,一块儿作变换,设置visibility等(Layer自己也是继承自view)。post
...
<androidx.constraintlayout.helper.widget.Layer android:id="@+id/mLayer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/shape_pet_white_with_corner" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="@id/mRecyclerView" app:constraint_referenced_ids="mTvTitle,mRecyclerView,guide_line" />
...
复制代码
自定义ConstraintHelper(简称Helper),能够用来封装针对ui的一些固定行为,方便之后复用。并且,一个view又能够同时被多个helper所引用,能够很便捷地组合出多种效果。性能
注:Helper自己也是继承了view的
app:constraint_referenced_ids="xxx,xxx"
class EnterAnimationHelper @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {
override fun updatePostLayout(container: ConstraintLayout?) {
super.updatePostLayout(container)
val views = getViews(container)
views.forEach {
startEnterAnimation(it)
}
}
private fun startEnterAnimation(view: View) {
val translationY = -100f
view.translationY = translationY
val translationYHolder = PropertyValuesHolder.ofFloat(
View.TRANSLATION_Y,
translationY,
0f
)
val keyFrame1 =
Keyframe.ofFloat(0f, -6f)
val keyFrame2 =
Keyframe.ofFloat(0.6f, 25f)
val keyFrame3 =
Keyframe.ofFloat(1f, 0f)
val rotateHolder =
PropertyValuesHolder.ofKeyframe(View.ROTATION, keyFrame1, keyFrame2, keyFrame3)
ObjectAnimator.ofPropertyValuesHolder(
view,
translationYHolder,
rotateHolder
)
.apply { interpolator = AnticipateOvershootInterpolator() }
.setDuration(600L)
.start()
}
}
复制代码
...
<com.cyq.x622.constraintlayoutsample.widget.EnterAnimationHelper android:layout_width="wrap_content" android:layout_height="wrap_content" app:constraint_referenced_ids="xxx,xxx" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
...
复制代码
效果以下(此处是封装了一个,上下位移和左右旋转的动画效果):
ConstraintLayoutStates能够建立具备不一样状态的布局并在它们之间轻松切换。一般,一个界面包含有加载状态,加载成功状态以及加载失败状态。利用ConstraintLayoutStates,能够很方便地在已定义好的状态之间相互切换。
根据须要,建立不一样状态下的布局文件。每个文件必须有相同的view,只有属性值,如visibility,和定位方式等能够不相同(简单起见,demo就定义了加载状态和成功状态,都是只含有一个ProgressBar和一个TextView,id都相同,只有visibility不一样)
在xml资源文件夹中,建立一份xml文件,定义了layout可拥有的全部状态constraint_set_test.xml:
<?xml version="1.0" encoding="utf-8"?>
<ConstraintLayoutStates xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<State android:id="@+id/loading" app:constraints="@layout/activity_state_start"/>
<State android:id="@+id/success" app:constraints="@layout/activity_state_end"/>
</ConstraintLayoutStates>
复制代码
在activity/fragment中,在要应用状态的ConstraintLayout上 使用loadLayoutDescription(),加载定义好的状态xml文件声明。而后即可以直接调用constraintLayout.setState()来切换状态.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_state_loading)
mStateConstraintLayout.loadLayoutDescription(R.xml.constraint_set_test)
//简单延时,模拟io操做
mStateConstraintLayout.postDelayed({
mTv.text = "加载完成"
mStateConstraintLayout.setState(R.id.success,0,0) //xml中定义的id
},4_000L)
}
复制代码
效果以下:
2.0之后,对属性的修改提供了流式API。
ConstraintProperties(mBtnLayer)
.alpha(0.5f)
.margin(ConstraintSet.TOP, 100)
.apply()
复制代码
这部分比较简单,能够直接查看官方文档ConstraintProperties
Flow是一个特别强大的布局辅助工具,支持多种布局模式,能够快速构造多样性布局。
Flow部分的demo及文中结构大部分翻译自于Medium:Awesomeness of ConstraintLayout Flow
尽管约束布局已经特别强大,能够快速创建约束关系展现布局,以下面两个水平关系view
两个水平view
但若是要构建8个不一样行的view,且相互之间有约束关系:
每行之间间隔均分
固然,使用三条约束链即可以实现,但写法上太过于繁琐,尤为是当垂直方向上还要设置对应关系时,更加繁琐。
这时候Flow就能够派上用场了。
Flow能够当作一个具备多种约束功能的流式布局,当空间不足时,能按设定的方式自动换行对齐。
Flow在使用上,有多个属性能够控制布局约束关系:
布局方向:水平horizonta l或 垂直vertical
setOrientation(int orientation)
android:orientation="horizontal|vertical"
水平布局
垂直布局
WrapMode属性决定了Flow将如何控制所引用的views的布局方法:NONE,CHAIN,ALIGN
app:flow_wrapMode = " none | chain | aligned "
flow.setWrapMode( Flow.WRAP_NONE | Flow.WRAP_CHAIN | Flow.WRAP_ALIGNED )
NONE:默认值,空间不够状况下Views不会被自动换到另外一行/列,直接超出屏幕范围。
Wrap Mode = NONE
CHAIN:该模式与约束布局的链式chain布局类似,不只能够实现相同的效果,还会额外的自动换行/换列处理
【注】:与约束布局链式布局同样,CHAIN模式也有链式style:SPREAD(默认值),PACKED,SPREAD_INSIDE
Wrap Mode = CHIAN 且 style = SPREAD
ALIGNED:该模式与上面的CHAIN相同,但额外增长了对齐方式
【注】:与CHAIN模式同样也有链式style:SPREAD(默认值),PACKED,SPREAD_INSIDE
Wrap Mode = ALIGNED 且 style = SPREAD
Gap是放置views时的水平和垂直间隔。 app:flow_horizontalGap
app:flow_verticalGap
flow.setVerticalGap
flow.setHorizontalGap
由于比较简单,就不放图了,手动试试就知道了。
当wrapMode为chain或ALIGNED时生效。Flow的styles跟约束布局以前的基础链式布局style是一个概念,有SPREAD(默认值),PACKED,SPREAD_INSIDE。不了解的可先查看上一篇:约束布局的链式布局
app:flow_horizontalStyle = “ spread | spread_inside | packed ”
app:flow_verticalStyle = “ spread | spread_inside | packed ”
应用到Flow中,效果以下:
spread
Spread Inside
packed
flow的bias偏移,只在style为packed时生效,由于当style为spread或者spread_inside时,views是均匀分布的,bias没法起到做用。float值,范围为 0-1
app:flow_horizontalBias = “ float "
app:flow_verticalBias = “ float "
flow.setHorizontalBias( float)
flow.setVerticalBias( float)
这里只取两个端点值,0和1,方便理解。
bias为0,贴到最左边
bias为1,贴到最右边
Alignment对齐方式,一样也有水平和垂直。Alignment的对齐方向,与flow的方向必须是相反的才能生效。好比当flow的方向是水平时,Alignment只有设为垂直才有效。views是水平放置,对齐是view与view之间在垂直方向上的对齐方式。关于这个属性,能够运行demo多试几遍理解理解。
app:flow_verticalAlignment = “ top | center | bottom | baseline ”
app:flow_horizontalAlignment = “ start| end ”
flow.setVerticalAlignment(
Flow.VERTICAL_ALIGN_TOP | Flow.VERTICAL_ALIGN_CENTER | Flow.VERTICAL_ALIGN_BOTTOM | Flow.VERTICAL_ALIGN_BASELINE )
flow.setHorizontalAlignment(
Flow.HORIZONTAL_ALIGN_START | Flow.HORIZONTAL_ALIGN_END )
复制代码
Vertical Alignment = Bottom
flow的demo并不是远程,可参考ConstraintFlowPlayground
MotionLayout是2.x版本的一个重要的更新,尤为是MotionLayout构建动态布局。下期再计划编写了