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構建動態佈局。下期再計劃編寫了