第 26 章的摘要。 自訂版面配置
注意
這本書於2016年春季出版,此後一直沒有更新。 這本書中有很多仍然有價值,但一些材料已經過時,有些主題不再完全正確或完整。
Xamarin.Forms 包含衍生自 Layout<View>
的數個類別:
StackLayout
,Grid
,AbsoluteLayout
,以及RelativeLayout
.
本章說明如何建立衍生自 Layout<View>
的類別。
版面配置的概觀
沒有處理 Xamarin.Forms 版面配置的集中式系統。 每個元素都負責判斷自己的大小應該是什麼,以及如何在特定區域內轉譯自己。
父項和子系
具有子系的每個元素都須負責將這些子系放在本身內。 最後決定其子系應該根據其可用大小和子系想要的大小,決定其子系的大小。
重設大小和定位
版面配置會從可視化樹狀結構的頂端開始,然後繼續進行所有分支。 配置中最重要的公用方法是由 Layout
VisualElement
定義。 每個元素都是其他元素的父代,都會為其每個子系呼叫 Layout
,讓子系以值形式 Rectangle
相對於本身的大小和位置。 這些 Layout
呼叫會透過視覺化樹狀結構傳播。
必須呼叫 Layout
,元素才會出現在畫面上,並導致設定下列只讀屬性。 它們與 Rectangle
傳遞至 方法的 一致:
Layout
呼叫之前,Height
且Width
具有 –1 的模擬值。
對 Layout
的呼叫也會觸發對下列受保護方法的呼叫:
SizeAllocated
,其會呼叫OnSizeAllocated
,可以覆寫。
最後,會引發下列事件:
方法 OnSizeAllocated
會由 Page
和 Layout
覆寫,這是中唯一可以有子系的 Xamarin.Forms 兩個類別。 覆寫的方法呼叫
UpdateChildrenLayout
適用於Page
衍生專案和UpdateChildrenLayout
Layout
衍生專案,其會呼叫LayoutChildren
適用於Page
衍生專案和LayoutChildren
Layout
衍生專案。
LayoutChildren
接著會針對每個元素的子系呼叫 Layout
。 如果至少有一個子系有新的 Bounds
設定,則會引發下列事件:
LayoutChanged
適用於Page
衍生專案和LayoutChanged
Layout
衍生工具
條件約束和大小要求
若要 LayoutChildren
以智慧方式呼叫 Layout
其所有子系,它必須知道 子系的慣用 或 想要 的大小。 因此,每個子系的呼叫 Layout
通常會在呼叫之前
出版書籍之後,方法 GetSizeRequest
已被取代,並取代為
方法 Measure
會容納 屬性, Margin
並包含 類型 MeasureFlag
為的自變數,其有兩個成員:
IncludeMargins
None
表示不包含邊界
對於許多元素, GetSizeRequest
或 Measure
從其轉譯器取得專案的原生大小。 這兩種方法都有寬度和高度 條件約束的參數。 例如, Label
會使用寬度條件約束來決定如何包裝多行文字。
和 都會GetSizeRequest
Measure
傳回 類型的SizeRequest
值,其具有兩個屬性:
通常這兩個值都相同,而且 Minimum
通常可以忽略該值。
VisualElement
也會定義類似於 GetSizeRequest
從 GetSizeRequest
呼叫的受保護方法:
OnSizeRequest
傳SizeRequest
回值
該方法現在已被取代,並取代為:
衍生自 Layout
或 Layout<T>
的每個類別都必須覆寫 OnSizeRequest
或 OnMeasure
。 這是配置類別決定自己的大小,這通常是根據其子系的大小,呼叫 GetSizeRequest
或 Measure
子系取得。 在呼叫 OnSizeRequest
或 OnMeasure
之前和之後, GetSizeRequest
或 Measure
根據下列屬性進行調整:
WidthRequest
型double
別 為 ,會影響 的Request
屬性SizeRequest
HeightRequest
型double
別 為 ,會影響 的Request
屬性SizeRequest
MinimumWidthRequest
型double
別 為 ,會影響 的Minimum
屬性SizeRequest
MinimumHeightRequest
型double
別 為 ,會影響 的Minimum
屬性SizeRequest
無限條件約束
傳遞至 GetSizeRequest
(或 Measure
) 和 OnSizeRequest
(或 OnMeasure
) 的條件約束自變數可以是無限的 (亦即 的值 Double.PositiveInfinity
)。 不過, SizeRequest
從這些方法傳回的 不能包含無限維度。
無限條件約束表示要求的大小應該反映元素的自然大小。 具有無限高度條件約束之子系的垂直 StackLayout
呼叫 GetSizeRequest
(或 Measure
)。 水平堆疊版面配置會在其子系上呼叫 GetSizeRequest
(或 Measure
) 並具有無限寬度限制。 AbsoluteLayout
在其子系上呼叫GetSizeRequest
具有無限寬度和高度條件約束的 (或Measure
)。
查看進程內部
ExploreChildSize 會顯示簡單版面配置的條件約束和大小要求資訊。
衍生自版面配置<檢視>
自訂版面設定類別衍生自 Layout<View>
。 它有兩個責任:
- 覆寫
OnMeasure
以呼叫Measure
配置的所有子系。 傳回配置本身的要求大小 - 覆寫
LayoutChildren
以呼叫Layout
所有版面配置子系
for
這些覆寫中的 或 foreach
循環應該略過屬性IsVisible
設定為 false
的任何子系。
不保證對的呼叫 OnMeasure
。 OnMeasure
如果版面配置父系控管版面配置的大小,則不會呼叫 (例如,填滿頁面的配置)。 基於這個理由, LayoutChildren
無法依賴呼叫期間取得的 OnMeasure
子大小。 通常, LayoutChildren
必須自行呼叫 Measure
配置子系,或者您可以實作某種大小的快取邏輯(稍後要討論)。
簡單的範例
VerticalStackDemo 範例包含簡化的VerticalStack
類別及其使用示範。
簡化垂直和水準定位
必須在覆寫期間LayoutChildren
執行的其中一個作業VerticalStack
發生。 方法會使用子系的 HorizontalOptions
屬性來決定如何將子系放在 其位置中 VerticalStack
。 您可以改為呼叫靜態方法 Layout.LayoutChildIntoBoundingRect
。 這個方法會在子系上呼叫 Measure
,並使用 其 HorizontalOptions
和 VerticalOptions
屬性,將子系放置在指定的矩形內。
失效
元素屬性的變更通常會影響該專案在版面配置中的顯示方式。 配置必須失效,才能觸發新的版面配置。
VisualElement
定義受保護的方法,這個方法 InvalidateMeasure
通常是由任何可系結屬性的屬性變更處理程式所呼叫,其變更會影響元素的大小。 方法 InvalidateMeasure
會引發 MeasureInvalidated
事件。
類別 Layout
會定義名為 InvalidateLayout
的類似受保護方法, Layout
其衍生工具應該針對會影響其位置及大小子系之方式的任何變更呼叫。
撰寫版面配置的某些規則
衍生專案定義的
Layout<T>
屬性應該受到可繫結屬性的支援,而屬性變更的處理程式應該呼叫InvalidateLayout
。Layout<T>
定義附加可系結屬性的衍生項目應該覆寫OnAdded
,將屬性變更的處理程式新增至其子系,並OnRemoved
移除該處理程式。 處理程式應該檢查這些附加可系結屬性中的變更,並藉由呼叫InvalidateLayout
來回應。Layout<T>
實作子大小快取的衍生專案,在呼叫這些方法時,應該覆寫InvalidateLayout
和OnChildMeasureInvalidated
清除快取。
具有屬性的版面配置
WrapLayout
Book.Toolkit 中的 Xamarin.Forms類別會假設其所有子系的大小都相同,並將子系從一個數據列(或數據行)包裝到下一個數據列。 它會定義 Orientation
屬性,例如 StackLayout
、 和 ColumnSpacing
等RowSpacing
Grid
屬性,而且會快取子大小。
PhotoWrap 範例會在 中ScrollView
放入 WrapLayout
來顯示股票相片。
不允許不受限制的維度!
Book.Toolkit 連結庫中的Xamarin.Forms 是用來顯示其本身的所有子系。 UniformGridLayout
因此,它無法處理不受限制的維度,如果遇到例外狀況,就會引發例外狀況。
PhotoGrid 範例示範UniformGridLayout
:
重疊子系
Layout<T>
衍生專案可以與其子系重疊。 不過,子系會依集合的順序 Children
轉譯,而不是呼叫其 Layout
方法的順序。
類別 Layout
會定義兩個方法,可讓您在集合內移動子系:
LowerChild
表示將子系移至集合的開頭RaiseChild
表示將子系移至集合結尾
對於重疊的子系,集合結尾的子系會在集合開頭以視覺方式出現在子系的頂端。
Book.Toolkit 連結庫中的Xamarin.Forms 類別會定義附加屬性來指出轉譯順序,因此允許其中一個子系顯示在其他子系之上。OverlapLayout
StudentCardFile 範例會示範下列專案:
其他附加的可系結屬性
Book.Toolkit 連結庫中的Xamarin.Forms 類別會定義附加的可系結屬性,以指定兩Point
個值和粗細值,並操作BoxView
元素以類似線條。CartesianLayout
UnitCube 範例會使用該範例來繪製 3D Cube。
版面配置與版面配置
Layout<T>
衍生專案可以呼叫 LayoutTo
而不是Layout
以動畫顯示版面配置。 類別 AnimatedCartesianLayout
會執行此動作, 且 AnimatedUnitCube 範例會示範它。