視頻:價(jià)值100w+Android項(xiàng)目實(shí)戰(zhàn)大全:手把手實(shí)戰(zhàn),自定義View
原文: https://juejin.cn/post/6969132819855441934
View的生命周期
先onMeasure()測量 、 再onLayout()布局 、最后onDraw()繪制。
在onMeasure()度量時(shí),會先去度量兒子(先走兒子的生命周期),想確認(rèn)兒子的大小才能確認(rèn)自己的大小。
自定義View分成兩類:
- 自定義View
一般繼承自View,SurfaceView或其他的View。
onMeasure()--> onDraw()都會執(zhí)行,onLayout()看需求
- 自定義ViewGroup
繼承自ViewGroup或各種Layout
onMeasure()--> onLayout()都會執(zhí)行, onDraw()看需求
自定義View包含什么
布局: onlayout onmeausre/ Layout:viewGroup
顯示: onDraw :view: canvas paint matrix clip rect animation path(貝塞爾) line text繪制 frameWork: 交互: onTouchEvent :組合的viewGroup
LayoutParams與MeasureSpec
LayoutParams
LayoutParams(布局參數(shù)),也就是xml里定義的
獲取
MeasureSpec
MeasureSpec是一個(gè)(32位)的int值,高兩位表示父容器對 view 的布局上的限制(Mode),低30位表示view的Size
1.unspecified--無限制
2.exactly -- 確定的大小
3.at_most -- 最大不超過
實(shí)現(xiàn)流式布局
1.繼承ViewGroup
2.自定義ViewGroup需要實(shí)現(xiàn)onMeasure()度量和onLayout()
4.兒子的寬高是根據(jù)父親給他的MeasureSpec的Mode + 上自己的LayoutParams算出來的,也就是上面的那個(gè)表格。如父親給的是exactly(確定的大小),兒子又是android:layout_width="10dp",兩個(gè)都是確定的,那就是10dp
5.取到兒子的寬高
6.兒子的寬高拿到了,那就是計(jì)算每行的寬度(并且取最大行寬度)。計(jì)算總的高度
7.for循環(huán)跑完了,這樣每個(gè)孩子都度量完了,也知道了最大的寬高,就可以度量自己的寬高了
8.但是自己的寬高并不只受兒子的影響,還跟父親給的Mode相關(guān)
到此onMeasure()度量完了,接下來開始布局onLayout()
9.因?yàn)槎攘康臅r(shí)候,已經(jīng)確定了每一行存哪幾個(gè)View,把他存到數(shù)組里,這樣布局的時(shí)候簡單很多
10.布局onLayout()重要的就是確定上下左右。
所謂的上下左右就是距離父親總邊框的左上角的位置
所以第一個(gè)view的左就是0,右就是 左+view的寬度。(計(jì)算時(shí)考慮view直接的margin就行)
第二個(gè)view就是 第一個(gè)View的右+第二個(gè)view的左....依次類推(用掉的寬高)
補(bǔ)充
view.getMeasuredWidth()與view.getWidth()
取寬高的時(shí)候?yàn)樯妒莢iew.getMeasuredWidth()。
view.getMeasuredWidth()度量之后這個(gè)就有值,但是view.getWidth()得view繪制完成
所以有的時(shí)候用view.getWidth()取值的時(shí)候是0,但是刷新一下或者下一個(gè)繪制時(shí)又有值了。
view的Visibility別忘了
是不是隱藏的情況得考慮