限制條件和修飾符順序

在 Compose 中,您可以將多個修飾符鏈結在一起,以變更可組合項的外觀與風格。這些修飾符鏈會影響傳送至可組合項的限制條件,也就是定義寬度和高度邊界。

本頁面說明鏈結修飾符如何影響限制,進而影響可組合項的測量結果和位置。

UI 樹狀結構中的修飾符

如要瞭解修飾符如何互相影響,建議您將這些修飾符在 UI 樹狀結構中 (在組合階段產生的) 中呈現的方式呈現。詳情請參閱「組合」一節。

在 UI 樹狀結構中,您可以將修飾符視覺化為版面配置節點的包裝函式節點:

可組合項和修飾符的程式碼,以及以 UI 樹狀結構形式呈現的元件程式碼。
圖 1 可在 UI 樹狀結構中包裝版面配置節點的修飾符。

只要在可組合項中加入多個修飾符,就會建立一連串修飾符。鏈結多個修飾符時,每個修飾符節點都會納入鏈結的其餘部分以及其中的版面配置節點。舉例來說,當您鏈結 clipsize 修飾符時,clip 修飾符節點會包裝 size 修飾詞節點,然後納入 Image 版面配置節點。

在版面配置階段,行走樹狀結構的演算法會保持不變,但會瀏覽每個修飾符節點。如此一來,修飾符就能變更其所包裝的修飾符或版面配置節點的大小要求和位置。

如圖 2 所示,ImageText 可組合項本身的實作方式是由包裝單一版面配置節點的修飾符鏈結組成。RowColumn 的實作只是版面配置節點,用來描述如何安排子項的版面配置。

之前的樹狀結構,但現在每個節點只是一個簡單的版面配置,還有許多修飾符圍繞節點環繞。
圖 2. 與圖 1 相同的樹狀結構,但 UI 樹狀結構中的可組合項會以視覺化方式呈現為修飾符鏈結。

總結:

  • 修飾符會納入單一修飾符或版面配置節點。
  • 版面配置節點可以配置多個子節點。

以下各節說明如何使用這個心理模型來解釋修飾詞鏈結,以及該模型如何影響可組合項的大小。

版面配置階段的限制

版面配置階段會按照三步驟演算法尋找每個版面配置節點的寬度、高度和 x Y 座標:

  1. 測量子項:節點測量其子項 (如有)。
  2. 決定自己的大小:節點會根據這些測量值決定節點大小。
  3. 放置子項:每個子節點都會根據節點自己的位置放置。

在演算法的前兩個步驟中,Constraints 會協助找出節點適用的大小。限制會定義節點寬度與高度的上下限。當節點決定其大小時,其測量大小應落在這個大小範圍內。

限制的類型

限制可以是下列其中一種:

  • Bounded:節點有寬度和下限上限。
容器中不同大小的界限限制。
圖 3. 受限限制。
  • 未界限:節點不受任何大小的限制。寬度和高度上限會設為無限大。
無界限,將寬度和高度設為無限。限制會超出容器範圍。
圖 4.不受限。
  • 完全比對:系統要求節點符合確切的大小規定。下限和上限會設定為相同的值。
符合容器中確切大小要求的確切限制。
圖 5.精確限制。
  • 組合:節點會遵循上述限制類型的組合。舉例來說,限制可以把寬度限定在不設限的高度上限,也可以設定確切寬度但提供有限的高度。
顯示限制與不受限限制,以及確切寬度和高度的兩個容器。
圖 6.限制與不受限限制的組合,以及確切的寬度和高度。

下一節將說明這些限制如何從父項傳遞至子項。

限制從父項傳遞至子項的方式

版面配置階段中的限制所述演算法的第一個步驟中,限制會從父項向下傳遞至 UI 樹狀結構中的子項。

父項節點測量子項時,會為每個子項提供這些限制,讓他們瞭解可設定的大小。之後,當它決定自己的大小時,也會遵循其本身父項所傳入的限制。

大致來說,演算法的運作方式如下:

  1. 在決定實際要佔用的大小時,UI 樹狀結構中的根節點會測量其子項,並將相同的限制轉送至其第一個子項。
  2. 如果子項是不會影響測量的修飾符,則會將限制轉送至下一個修飾符。除非觸及會影響測量的修飾符,否則這些限制會依原樣向下傳遞給修飾符鏈。然後,這些限制會隨之重新調整。
  3. 到達沒有任何子項 (稱為「分葉節點」的節點) 後,就會根據傳入的限制決定其大小,並將這個已解析的大小傳回其父項。
  4. 父項會根據此子項的測量值調整其限制,並以這些經過調整的限制來呼叫下一個子項。
  5. 測量父項的所有子項後,父項節點會決定其自己的大小,並將這個大小傳達給其父項。
  6. 如此一來,整個樹狀結構都會先進行深度掃遍。最後,所有節點都決定了大小,評估步驟也已完成。

如需詳細範例,請參閱「限制和修飾符順序」影片。

影響限制的修飾符

您在先前的章節中學到,有些修飾符會影響限制大小。以下各節說明會影響限制的特定修飾符。

size 個修飾符

size 修飾符會宣告內容的偏好大小。

舉例來說,下列 UI 樹狀結構應由 200dp300dp 的容器中轉譯。限制條件設有界限,允許介於 100dp300dp 之間的寬度,高度介於 100dp200dp 之間:

UI 樹狀結構的一部分,使用大小修飾符包裝版面配置節點,以及容器中大小修飾符設定的受限限製表示法。
圖 7. UI 樹狀結構中的邊界限制及其在容器中的呈現方式。

size 修飾符會調整傳入的限制,使其符合傳遞的值。在這個範例中,值為 150dp

與圖 7 相同,除了大小修飾符會調整傳入限制,以比對傳遞至的值。
圖 8.size 修飾符會將限制調整為 150dp

如果寬度和高度小於最小限制範圍,或大於最大限制邊界,修飾符會盡可能比對通過的限制,但仍遵循傳入的限制:

兩個 UI 樹狀結構及其在容器中對應的表示法。其一是大小修飾符接受遞增限制,第二種大小修飾符會盡可能適應過大的限制條件,導致會填滿容器的限制。
圖 9.size 修飾符會盡可能符合傳遞的限制。

請注意,鏈結多個 size 修飾符無法運作。第一個 size 修飾符會將最小和最大限制設定為固定值。即使第二個大小修飾符要求較小或更大尺寸,仍需要符合傳入的確切邊界,因此不會覆寫這些值:

UI 樹狀結構中的兩個大小修飾符鏈結及其在容器中的表示法,這是傳入的第一個值,而非第二個值的結果。
圖 10.兩個 size 修飾符的鏈結,其中傳入的第二個值 (50dp) 不會覆寫第一個值 (100dp)。

requiredSize 個修飾符

如果您需要節點覆寫傳入的限制,請使用 requiredSize 修飾符,而非 sizerequiredSize 修飾符會取代傳入的限制,並將您指定的大小做為確切邊界傳遞。

大小向上傳遞至樹狀結構後,子項節點會在可用空間的中央:

UI 樹狀結構中鏈結的大小和 requiredSize 修飾符,以及容器中對應的表示法。requiredSize 修飾符限制會覆寫大小修飾符限制。
圖 11.requiredSize 修飾符會覆寫來自 size 修飾符的傳入限制。

widthheight 修飾符

size 修飾符會調整限制條件的寬度和高度。使用 width 修飾符,您可以設定固定寬度,但不要決定高度。同樣地,使用 height 修飾符時,您可以設定固定高度,但不要決定寬度:

兩個 UI 樹狀結構,一個帶有寬度修飾符及其容器表示法,另一個使用高度修飾符及其表示法。
圖 12.width 修飾符和 height 修飾符分別設定了固定寬度和高度。

sizeIn 個修飾符

sizeIn 修飾符可讓您針對寬度和高度設定確切的最小和最大限制。如果您需要精細控管限制,請使用 sizeIn 修飾符。

含有 sizeIn 修飾符的 UI 樹狀結構,且設有最小和最大寬度與高度,以及容器中其呈現方式。
圖 13.已設定 minWidthmaxWidthminHeightmaxHeightsizeIn 修飾符。

範例

本節會顯示並說明數個含有鏈結修飾符的程式碼片段輸出內容。

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .size(50.dp)
)

這個程式碼片段會產生以下輸出內容:

  • fillMaxSize 修飾符會變更限制條件,將最小寬度和高度設為最大值,寬度為 300dp,高度為 200dp
  • 即使 size 修飾符想使用 50dp 的大小,仍需要遵循傳入的最小限制。因此,size 修飾符也會輸出 200300 確切限制邊界,有效忽略 size 修飾符中提供的值。
  • Image 會遵循這些邊界,並依照 200 回報 300 的大小,並將其傳遞至樹狀結構中。

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .wrapContentSize()
        .size(50.dp)
)

這個程式碼片段會產生以下輸出內容:

  • fillMaxSize 修飾符會調整限制條件,將最小寬度和高度設為最大值 - 寬度為 300dp,高度設為 200dp
  • wrapContentSize 修飾符會重設最小限制。因此,雖然 fillMaxSize 導致限制固定,但 wrapContentSize將其重設為受限的限制條件。下列節點現在可以再次佔據整個空間,或小於整個空間。
  • size 修飾符會將限制設為 50 的上下限。
  • Image 會由 50 解析為 50 的大小,size 修飾符則會轉向此大小。
  • wrapContentSize 修飾符具有特殊屬性。系統會擷取其子項,並將其置於傳遞給它的可用最低邊界中心。因此,其傳達給父項的大小等於傳入的最小邊界。

只要結合三個修飾符,就能定義可組合項的大小,並將其置於其父項中心。

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .clip(CircleShape)
        .padding(10.dp)
        .size(100.dp)
)

這個程式碼片段會產生以下輸出內容:

  • clip 修飾符不會變更限制條件。
    • padding 修飾符會降低限制條件上限。
    • size 修飾符會將所有限制條件設為 100dp
    • Image 遵循這些限制,並依照 100dp 回報 100 的大小。
    • padding 修飾符會為所有大小加上 10dp,因此回報的寬度和高度會增加 20dp
    • 在繪圖階段,clip 修飾符會在 120120dp 畫布上執行。因此,系統會建立該大小的圓形遮罩
    • 接著,padding 修飾符會在所有大小的 10dp 上將內容插邊,因此將畫布大小減少為 100dp100
    • Image 會顯示在該畫布中。圖片是根據 120dp 的原始圓形裁剪,因此輸出內容為非圓形結果。