Jetpack Compose的Modifier順序問題
一:前言
困惑起源於這段程式碼
Composable.clickable(點擊1).clickable(點擊2).size(100.dp).size(200.dp){ ............... }
Composable是隨便一個@Composable函數。結果是:點擊二會應用,size100dp會應用。
一開始,我試驗size的時候,以為是modifier從右往左應用的,但clickable的處理顯然違背了這個事實,再放多一個實例
Text("Hi there!", Modifier.padding(10.dp).border(2.dp, Color.Magenta))
這是一個stack overflow的問題,顯示結果如下:
他因此疑惑,modifier應該是從右往左應用的吧,先border,再padding,十分合理。
二:先上結論
- modifier的應用既不是從左往右,也不是從右往左,而是從左往右,然後從右往左回來。
- modifier有很多種類,既有控制觸摸的pointer modifier,也有border的draw modifier,也有padding/size這些layout modifier
- layout modififier和其他modifier的處理都不一樣,layout modifier會從左往右傳遞constraint,又從右往左傳遞size回來。也就是說,layout modifier是左到右,然後右到左走兩遍,其他modifier是從右到左只走一遍。
- constraint是約束的意思,類似於view系統中的MeasureSpec,不過constraint做的更多,可以抽象成擁有四個參數,最小寬,最大寬,最小高,最大高。左邊的layout modifier把constraint 傳給右邊的layout modifier,右邊的layout modifier測量之後,把尺寸資訊傳給左邊。
- layout modifier都有一個measure方法用來測量大小。
三:上示例解釋
Box(modifier = Modifier.height(200.dp).width(250.dp)){ Text("Hello, honey?", Modifier .fillMaxSize() .padding(10.dp) .size(100.dp) .border(1.dp, Color.Black) .size(200.dp)) }
最外面的box僅僅起到一個控制範圍的作用,不要考慮,我們要做的是分析這個text的modifier。
開始嘍!!!
1: 首先,最外面的Box給到第一個modifier 約束,如圖所示。
2:fillmaxsize會把約束都撐大,因此它測量下一個modifier給到的約束是min max都為一個固定最大值。
3:padding收到約束,因為它需要四周留空。這裡插一個小知識,modifier是針對當前composable自身的,和content無關。因此padding考慮它自身一定要留空那麼多padding,所以它會像一個吝嗇地主那樣,把錢剋扣很多之後,才給它下面的員工。因此它把約束都減掉2 * padding。圖中畫錯了,因該是230 和 180.
4: size收到約束,它一看,你TM給我那麼多空間嗎!!太好了吧!!可是我不需要那麼多,我只需要100,我把約束設為100,然後傳給下一個。
5:border不是layout modifier不會對約束處理,它是從右往左的時候才會應用的。直接把約束傳過去。
6:size200對於上面把約束固定死了的,無能為力,繼續傳100.
7: 最後,整個text收到100 x 100的資訊,它就把自己size設為100 x 100,然後把size資訊(藍色部分)傳上去
6:size200不更改這個100 x 100的size資訊,繼續傳上去
5:size資訊傳到border這裡,添加了border資訊。
4:傳到size100這裡,繼續把size資訊傳上去
3:padding加上約束,size變為120 x 120, 這裡注意啦,先添加的border資訊,再添加的padding資訊!!!,這解釋了stack over flow那個問題。
2:120 x 120傳到fillmaxsize這裡,它很霸道啊,利用下面傳上來的資訊測得最終大小竟然是250 x 200。
1:Box get it!!心領神會!!
備註: 在從左往右的時候,是約束constraint的傳遞,會跳過非layout modifier。layout modifier可能修改約束,也可能不修改約束。從右往左的時候,在layout modifier之間傳遞的,是右邊的modifier測得的size大小資訊,以及如何擺放等資訊,遇到非layout modifier,會添加額外資訊!!
四: 源碼上
主要涉及LayoutNode,過幾天補充。
參考資料:
//www.youtube.com/watch?v=zMKMwh9gZuI&t=1043s&ab_channel=AndroidDevelopers
//developer.android.com/codelabs/jetpack-compose-layouts#8
星標://stackoverflow.com/questions/64206648/jetpack-compose-order-of-modifiers
//joebirch.co/android/exporing-jetpack-compose-padding-modifier/