一 束缚布局2.x新特性简介
What’s New in ConstraintLayout (Google I/O’19)
2020.06.28更新: Flow运用详解
束缚布局2.0未运用过束缚布局的,可先检查上一篇文章Const. 8 | n – |raf p 3 R z N s 5intL, ? o + , z r |ayout 束缚布局1.x
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3'
束缚布局是一个允许你灵敏界说view
方位和大小的ViewGroup
,具d O :有多种辅助工具,如GuideLine、Barrier、Group等。在灵敏地放H 3 O v [ v P置各种各样的view时,并不会添加Layout层级。2.0版别出了优化布局性能外,还添加了一些新特性,使得p I (开0 f H k Q发过程愈加方便:
- ConsN } 3 ! &traintHelper辅助工具的添加:Layer,flow。
- ConstraintHelper的自界说敞开
- ConstraintLayoutStates 界面状况切换控制
- API运用优化
- **MotionLayout **构建一个动态的布局
开发实际发现,到现在居然还有些人看不上束缚布局,Google对于束缚布局的信心和野心,莫非还不足以引起注重??
二 ConstraintHelper辅助工具
2.1 Layer
Layer功用上能够了解为包括它所引证的view的一个父布局viewGroup,但并不会添加layout的层级。这点对错常好用的,在Layer之前,想往自己view统& * z ; D一加个布景限制,一般都是别的加个view来做纯布景展现。
像开发过程中这种带图标的dialog,能U C ; b F够用la_ ) ryer8 3 g x R + O P x方便圈w : O = v出布景。
别的,Layer支撑对里面的 view 一同做改换,可看待成一个平常的父布局,一同做改换,设置visibility等(Layer本身也是承继自view)。
...
&le : * j 9t;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_constraiM - )ntStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf=S F _ z [ O"@id/mRecyclerView"
app:constraint_rs Q (eferenced_ids="mTvTitle,mRecyclerView,guide_li~ ` V 9ne"
/>
...
2.2 自界说 ConstraintHelper
自界说ConstraintHelpeQ m 6 *r(简称Helper),能够用来封装针对ui的一些固定行为,方便今后复用。并且,一个view又能够同时被多个helper所引证,能够k l 4 $ 3 c . s很便捷地组合出多种效果。
注:Helper本身也是B ( h C ^ . x Y ^承继了view的
- Helper @ W / 5 Pr供给了getViews()办法获取所引证的一切view
- Helper供给了view的onLayon h 8 c I Uut()^ , +/onMe1 G 1 H n ,asure()等流程办法执行前后的回调,如:updatePostLayout(container: ConstraintLayout?),onLayout()后 ;updatePreLayout(container: ConstraintLayout?) ,onLayout()前; 可d y Q | A R y B运用这些办法和获得的view,D Y r } h封装一些通用操作
- 再应用到布局文件中,声明要包括的view的id:
app:constraint_referenced_ids="xxx,xxx"
class EnterAnimationHelper @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : Coh s : 3 tnstz C . G u E J oraintHelper(context, attrs, defStyleAttr) {
override fun updateE o mPostLayout(container: ConstraintLayouB A 1t?) {
super.updatePostLayout(container)
val views = getViews(container)
views.fc ~ J # s N ] X yorEach {
startEnterAnimation(i~ _ 9 { } o ^t)
}
}
private fun startl d Y } J v vEnterAnimation(vM i v r 7 7 L % 0iew: View) {
val translationY = -100f
view.translationY = translationY
val tran9 S k ! [ 4 CslationYHolder = PropertyValuesHolder.ofFloZ $ D _ . u @ jat(
View.TRANSLATION_Y,
translationY,
0f
)
val kek Z /yFrame1 =
Keyframe.ofFloat(0f, -6f)
val keyFrame2 =
Keyframe.ofFloat(0.6f, 25f)
val keyFrame3 =
KeyfE V /rame2 l R m H.ofFloat(1f, 0f)
val rotateHolder =
PropertyValuesHolder.ofKeyframe(View.ROTATION, keyFrame1, keyFq ^ [rame2, keyFrame3)
ObjectAnimator.ofP* - n & ^ & i # `ropertyValuesHolder(
vie| = @ c N 6 c [ ow,
translationYHolder,
rotateHolder
)
.applyQ A v ( s { interpolator = AnticipateOver3 R 7 P 9 + NshootInterpolator() }
.setDuration(600L)
.start()
}
}
...
<com.cyq.x622.constraint_ i H | ^ u glayoutsample.widget.EnterAnimatio A f ]onHelper
az A U Q ? 5ndroiZ [ O i {d:layou0 } j 0t_widt0 Q 5 6 wh="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="xxx,xxx; # B"
app:layout_constrag * 9intStart_toStartOf="parent"
app:layout_# j P kconstraintTop_toTopOf="parent"
/>
...
效果如下(此处z e x ` ` I是封装了一个,上下位移和左右旋转的动画效果):
三 ConstraintLayouX 9 }tStates
ConstraintL n | T w I mLayoutStates能够创立具有不同状况的布局并在它们c z x J 8 J之间轻松切换。通常,一个界面包括有加载状况,加载成功状况以及加载失利状况。运用ConstraintLayoutStates,能够很方便地在已界说好的状况之间相互切换。
3.1 创立不同状况的布局文件
根据需要,创立不同状况j N V ` s H下的布局文件。每一个文件有必要有相同的view,只有特点值,如visibility,和l w { 5 z ! $ .定位方法等能够不相同(简单起见,demo就界说了I x F E y 1 i R加载状况和成功状况,都是只含有一个ProgressBar和一个TextView,id都相同,只有visibility不同)
3.2 创立状况声明XML文件
在xe $ 8 gml资源文件夹中,创立一份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 M Z m F 2 g ;p="http://schemas.android.com/apk/res-auto">
<State
android:id="@+id/loadin! s M 1 9 +g"
app:constraints="@layout/activity_state_start"/>
<State
android:id="@+id/success"
app:c: 8 ) Xonstraints="@layout& b A N b/activity_statk f b 2 se_end"/&g ` b zgt;
</ConstraintLayoU U ? c Z Iut* { ~ z ` q 7 @ RStates>
3.3 加载声明的状况文件并在不同状况之间切换, Y 5
在activity/fragment中,在要应用状况的ConstraintLayout上运用loadLayoutDescription* G ( & L = { 6 ?(),加载界说好的状况xml文件声明。然后便能够直接调用constraintLayout.setState()来切换状Y n r 0 C } #况.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_state_loading& } A i ^ H c)
mStateConstraintLayout.loadLayoutDescr} t c V [ H iiption(R.xml.constraint_J ` 0 c @ u X J set_test)
//简C : W y - $ v单延时,模拟io操作B ; S U Z p @
mStateConstraintLayout.postDelayed({
mTv.text = "加载完成"
mStateConstraintLayout.setState(R.# n l 0 o Yid.success,0,0) //xml中界说的id
},4_000L)
}
效果如下:
四 流式API
2.0今后,对A q d q $ W D特点的修改供给了流式API。4 3 l f Z Q
ConstraintProperties(mBtnLayer)
.alpha(u A o t ( ` F J ,0.5f)
.margin(Conp / + 8 / EstraintSet.TOP, 100)
.apply()
这部分比较简单,能够直接检查官方文档Cons: E o 0 L O q FtraintProperties
五 简易demo
附件:constraintLayout.zip
六 Flow
Flow是一个特别强壮的布局辅助工具,支撑多种布局形式,能V V v I H % – – w够快速构造多样性布局。
Flow部分的demo及} + + # * 3 s 8 u文中结构大部分翻译自于Medium:Awesomeness of ConstraintLayout Flow
尽管束缚布局已经特别强壮,能m u v X v 4 l够快速树立束缚联系展现G _ 8 J ^ 布局,如下面两个水平联系view
两个水平view
但假如要构建8个不同^ 9 ) ) O w行的view,且相互之间, R * f 5 z f _ H有束缚联系:
每行之间距离均分
当然,运用三条束缚链便能够实现,但写法上太过于繁琐,尤其o ; + _ K t I 是当m { = M + ! J笔直方向上还要设置对应联系时,愈加繁琐。
这时候Flow就能够派上用场了。
Flow能够看成一个具有多种束缚功用的流式布局,当空间不足时,能按设定的方法主动换行对齐。
Flow在运用上,有多个特点能够控制布局束缚联系:
- orientation: horizontal 或者 vertical
- WrapMode
- Gap
- Styles
- Bias
- Alignment
6.1 orientation
布局方向:水平horizonta l或 笔直vertical
setOrientation(int orientation)
android:orientation="horizontal|vertical"
水平布局
笔直布局
6.2 WrapMode
WrapMode特点决定了Flow将怎么控制所引证的views的布局办法:NONE,CHAIN,ALIGN
app:flow_wrapMode = " none | chain | aligned "
flow.setWrapMode(a b ! % K t ^ Flow.WRAP_NONE | Flow.WRAP_CHAIN | Flow.WRAP_ALIGNED )
NONE:默认值,空间不行情况下Views不会被主动换到另一行/列,0 : s V直接超出屏幕范围。
Wrap Mode = NONE
CHAIN:该形式与束缚布局的链式chain布局类似,不仅能够实现相同的效果,还会额定的主动换行/换– Z T [ k D 0 1 7列处理
【注】:与束缚布局链式布局相同,CH) a 2 G [ EAIN形式也有链式style:SPREAD(默认值),PACKED,SPREAD_INSIDE
Wrap Mode = CHIAN 且 style = SPREAD
ALIGNED:该形式与上面的CHAIN相同,但额定添加了对齐方法
【注】:与CHAIN形式相同也有链式style:SPREAD(默认值),PACKED,q ! C & 3SPREAD_INSI6 8 h _ | q TDE
Wrap Mode = ALIGNED 且 style = SPREAD
6.3 Gap
Gap是放置views时的水平缓笔直距离。
app:flow_horizontalGap
app:flow_, P { | J _ 2 cverticalGap
flow.setVerticalGap
fr 4 j ^low.setHorizonta, & ] glGap
因为比较简单,就不放图了,手动试试就知道了。
6.4 Styles
当wrapMode为chain或ALIGE 2 ~ 8 b 7 FNED时收效。Flow的styles跟束缚布局之前的根底链式布局style是一个概念,有SPREAD(默认值),PACKED,SPREAD_INSIDE。不了解的可先检查上一篇:束缚布局的链式布局
app:u i zflow_horizontalStyle = “ spread | spread_inside | packed ”
app:flow_verticalStyle = “ spread | spread_inside | packed ”
应! V q X u g用到Flow中,效果如下:
spread
Spread Inside
packed
6.5 Bias
flow的bias偏移,只在style为packed时收效,因为当style为spread或者spread_inside时,views是均匀分布的,bias无法起到效果。float值,范围为 0-1
app:flow_horizontalBias = “ fE 5 z Eloat "
app:flowy a v !_verticalBiasP s ~ = “ float "
flow.setHorizontalBias( float)
flow.setVerticalBias( float)
这儿只取两个端点值,0和1,方便了解。
bias为0,贴到最左面
bias为1,贴到最右边
6.6 Alignment
Alignment对齐方法,同样也有水平缓笔直。Alignment的对– m S D o V ?齐方向,与flow的方向有必要是相反的才能收效T = w c T 5 R t。比如当flow的方向是水平常,Alignment只有设为笔直才有效。viewsr 3 Y D是水平放置,对齐是view与view之间在笔直方向上的对齐方法。关于这个特点,w K { j .能够运转demo多试几遍了解了解。
app:flow_verticalAlignment = “ top | center | bottom | baseline ”
app:flow_horizontalAligq 4 ? K W Rnment = “ start| endJ l o ~ b O ”
flow.setVerticalAlignm; h T uent(
Flowp o U.VERTICAL_ALQ m ` w ? k n EIGN_TOP | Flow.VERTICAL_ALIB 4 b L H @ t NGN_CENTER | Flow.VERTICA{ q c Y $ SL_A$ 6 ^LIGN_BOTTO@ _ 9 ( bM | Flow.VERTICAH 1 c o C |L_ALIGN_BASELINE )
flow.setHorizontalAlignment(
Flow.Hd 5 V , T ^ sORIZONTAL_ALIGN_START | Flow.HORIZONTAL_ALIGN_END )
Vertical Alignment = Bottom
6.7 Flow demo
flow的demo并非长途e S S 2 : U ^ {,可参阅ConstraintFlowPlayground
后期方案MotionLayout
MotionLayout是2.x版t b _ b p { z 3别的一个重要的更新,尤其是MotionLayout构建动态布局。下期再方案编写了