Jetpack Compose的Modifier順序問題

靈劍山真人發表於2021-12-19

一:前言

困惑起源於這段程式碼

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,過幾天補充。

 

 

參考資料:

https://www.youtube.com/watch?v=zMKMwh9gZuI&t=1043s&ab_channel=AndroidDevelopers

https://developer.android.com/codelabs/jetpack-compose-layouts#8

星標:https://stackoverflow.com/questions/64206648/jetpack-compose-order-of-modifiers

https://joebirch.co/android/exporing-jetpack-compose-padding-modifier/

 

相關文章