DEVLOG 10.9 FrameLayout & addView

問題1:在這段代碼中 為什么不能將addView放到最底下?
如果將最后一行addView放到最底下,會出現(xiàn)NPE,表示layoutParams不能從textView中獲取到。所以這個問題就轉(zhuǎn)化成兩個子問題:
原本的View中LayoutParams都是空的嗎?
addView是如何處理LayoutParams的呢?

1, View中的LayoutParams都是空的嗎?

從文檔中我們可以看出View#getLayoutParams方法會在兩種情況下返回空:
- 如果當前的子View沒有attach到ViewGroup
- 如果setLayoutParams沒有正常生效
在View中,只有View#setLayoutParams將外界傳入的View綁定到View的全局參數(shù)LayoutParams:
在綁定成功之后,會重新請求布局,所以ViewGroup會考慮更新之后的LayoutParams。
如果不使用setLayoutParams,View中的LayoutParams為空。(當然,如果通過解析xml的方式也算設(shè)置了LayoutParams)
所以,我們可以通過addView將子View添加到(attach)到ViewGroup,所以為了避免下面出現(xiàn)異常,我們需要先進行addView。

2, addView對于LayoutParams的處理
根據(jù)addView的重載方法來看,addView也有不接收LayoutParams的重載方法:

不過這個方法也會調(diào)用View#getLayoutParams。如果是直接指定寬高的addView重載,會生成默認的LayoutParams:
綜上所述,上面的代碼中沒有必要使用LinearLayout.Params,因為GridLayout并沒有重載addView,可以直接使用LayoutParams,不需要考慮子類。當然直接指定寬高的話也可以,代碼可以這樣寫:

Scroller View#scrollTo? View#scrollBy? View#computeScroll
農(nóng)夫三拳:Scroller#startScroll View#computeScroll postInvalidate
拿我在這篇文章畫的這個圖為例:

Scroller需要調(diào)用startScroll作為滑動開始信號,View中需要實現(xiàn)computeScroll計算是否完成滑動,然后調(diào)用自身scrollTo滑動到確定的位置,最后調(diào)用postInvalidate更新。
用invalidate也行,postInvalidate 和 invalidate的區(qū)別在于invalidate會立刻重繪,postInvalidate可以從非UI線程,發(fā)送一條消息到UI線程的Handler,再重繪View。