MeasureSpec 是 View 底下的 static class。
首先要先理解各個階段 View 所做的事情
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
在此階段,View 會依據 Super View 所賦予的 widthMeasureSpec 與 heightMeasureSpec 去測量此 View 所要的長(measuredHeight)與寬(measureWidth)。
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
}
onLayout 是用來設定繪製 View 的邊界
大概是像這樣,也就是基於 Super View,child view 可以繪製的範圍。
onDraw 會傳入 canvas,View 就是畫在 canvas 上的!!
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
}
自定義 View 的繪製流程:
使用 inflater 製作出一個 View
var view = layoutInflater.inflate(R.layout.child_view, null, false)
接著設定 View 的 LayoutParams
view.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
那什麼是 LayoutParams 呢?
<android.support.constraint.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:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
....
</android.support.constraint.ConstraintLayout>
這是在 xml 裡面的 UI,在 ConstrintLayout 也就是 View,有兩個 tag ,分別是,這個就是 LayoutParams,Super View 會根據 LayoutParams 的不同而設定不同的 MeasureSpec Mode。
android:layout_width="match_parent"
android:layout_height="match_parent"
Super View 使用 MeasureSpec 為 child view 騰出一個空間。
設定對應的 MeasureSpec.makeMeasureSpec。
var width = MeasureSpec.makeMeasureSpec(this.measuredWidth, MeasureSpec.AT_MOST)var height = MeasureSpec.makeMeasureSpec(this.measuredHeight, MeasureSpec.AT_MOST)
設定 view 上面顯示的資料(一定要在 measure 前設定),否則 measure 出來的長與寬會不正確。
view.textView.text = "hello \n James"
接著讓 Child View 自己決定要多大的空間
view.measure(width, height)
注意:在 measure 之後,view.measuredWidth 以及 view.measuredHeight 就會有測量完的寬與高了
使用 view.layout 將 view 設定在合適的位置
view.layout(0, 0, view.measuredWidth, view.measuredHeight)
最後將 View 畫在 canvas 上
view.draw(canvas)
MeasureSpec 相關參數:
UNSPECIFIED:不限制 Child View 如何渲染,Child View 會超出 Super View 的範圍(Scroll View)。
EXACTLY:Child View 必須提供一個確切的長與寬。
AT_MOST:Child View 所設定的長與寬最大只能與 Super View 一樣大。
Android 設計 View 的邏輯
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
View 的大小是由 Super View 與 Child View 共同決定的,那 Root View 並沒有 Super View,以上述的例子來解釋
ConstraintLayout 的 layout_height 做了兩件事情:
- 與 ConstraintLayout 的 Super View 一起 measure ConstraintLayout。
- 扮演 TextView 的 MeasureSpec,並與 TextView 一起 measure TextView。