限制條件和修飾符順序

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

本頁說明鏈結修飾符如何影響限制條件,以及可組合項的測量和位置。

UI 樹狀結構中的修飾符

如要瞭解修飾符如何相互影響,建議您以視覺化方式呈現修飾符在組合階段所產生 UI 樹狀結構中的顯示方式。詳情請參閱「組合」一節。

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

可組合項和修飾符的程式碼,及其以 UI 樹狀結構的視覺化方式呈現。
圖 1 修飾符會包裝 UI 樹狀結構中的版面配置節點。

在可組合函式中加入多個修飾符,會建立修飾符鏈結。鏈結多個修飾符時,每個修飾符節點都會納入鏈結的其餘部分和版面配置節點中。舉例來說,當您鏈結 clipsize 修飾符時,clip 修飾符節點會納入 size 修飾符節點,然後包裝 Image 版面配置節點。

在版面配置階段,引導樹狀結構的演算法維持不變,但也會造訪每個修飾符節點。如此一來,修飾符就能變更其包裝的修飾符或版面配置節點的大小需求和位置。

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

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

總結:

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

以下各節將說明如何使用這個心理模型,推斷修飾符鏈結及其對可組合項大小的影響。

版面配置階段的限制

版面配置階段遵循三步驟演算法,找出每個版面配置節點的寬度、高度和 x、y 座標:

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

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

限制的類型

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

  • 有界限:節點的寬度和高度皆達到上限。
容器中不同大小的有限限制。
圖 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 修飾符也會根據 200 輸出 300 的確切限制範圍,有效忽略 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 修飾符會在由120的畫布上 120dp執行。因此,這項功能會建立該尺寸的圓形遮罩
    • 接著,padding 修飾符會對所有大小的內容加上 10dp 的插邊,使畫布大小依 100dp 調降為 100
    • Image 會在該畫布上繪製。圖片會根據 120dp 的原始圓形裁剪,因此輸出內容是非圓形的結果。