學習目標
- AbsoluteLayout 用法
- 如何設定已存在元素之 Attached bindable properties
在前面的章節已經學過 ContentView, Frame, ScrollView 和 StackLayout 這幾個掌控畫面元件位置的 "畫板"。
而 AbsoluteLayout 顧名思義就是一個提供 "絕對位置" 的畫板。
不像 StackLayout 可以利用 HorizontalOptions 或 VierticalOptions 自動堆疊元件的位置。
在 AbsoluteLayout,你只能 自己指定 元件的位置。
而這章節有個前面沒看過的特殊屬性 -- Attached bindable property
用來 "再次設定" 已存在 AbsoluteLayout 內的元件。
AbsoluteLayout
唯一和 StackLaout 一樣的是可以增加子元素:
absoluteLayout.Children.Add(child);
但在 AbsoluteLayout 增加子元素時,能夠同時帶入 Rectangle 這結構參數:
什麼是 Rectangle?
是一種包含 x, y 座標 及 寬高 4 個屬性的結構:
Point point = new Point(x, y); Size size = new Size(width, height); Rectangle rect = new Rectangle(point, size); //帶入 rect 結構 absoluteLayout.Children.Add(child, rect);
這樣就能決定物件在 AbsoluteLayout 內的位置!
另外,如果要讓系統自己計算 child 的大小(寬高),也可以只帶入 Point 就好:
absoluteLayout.Children.Add(child, point);
假設今天要做緞帶的效果如下圖,AbsoluteLayout 就能派上用場:
其原理是將四個 BoxView 相疊:
AbsoluteLayout 最大的 特色(缺點),就是元件位置要自己計算,如上面的範例內加了兩個 Label ,如果你要加入第三個 Label 時,座標應該為何??
但事實上,你可以把 Label 放在 StackLayout 內自己堆疊位置,再將 StackLayout 放到 AbsoluteLayout 內 (Layout 允許巢狀) ~
相比之下,StackLayout 使用上還是比 AbsoluteLayout 方便...
但許多特殊情況我們還是需要 AbsoluteLayout。
public class AbsoluteDemoPage : ContentPage { public AbsoluteDemoPage() { AbsoluteLayout absoluteLayout = new AbsoluteLayout { Padding = new Thickness(50) }; //在 absoluteLayout 加入四個 BoxView absoluteLayout.Children.Add(new BoxView { Color = Color.Accent }, new Rectangle(0, 10, 200, 5)); absoluteLayout.Children.Add(new BoxView { Color = Color.Accent }, new Rectangle(0, 20, 200, 5)); absoluteLayout.Children.Add(new BoxView { Color = Color.Accent }, new Rectangle(10, 0, 5, 65)); absoluteLayout.Children.Add(new BoxView { Color = Color.Accent }, new Rectangle(20, 0, 5, 65)); //加入 Label absoluteLayout.Children.Add(new Label { Text = "Stylish Header", FontSize = 24 }, new Point(30, 25)); absoluteLayout.Children.Add(new Label { FormattedText = new FormattedString { Spans = { new Span { Text = "Although the " }, //...以下省略 } } }, new Point(0, 80)); this.Content = absoluteLayout; } }
AbsoluteLayout 最大的 特色(缺點),就是元件位置要自己計算,如上面的範例內加了兩個 Label ,如果你要加入第三個 Label 時,座標應該為何??
但事實上,你可以把 Label 放在 StackLayout 內自己堆疊位置,再將 StackLayout 放到 AbsoluteLayout 內 (Layout 允許巢狀) ~
相比之下,StackLayout 使用上還是比 AbsoluteLayout 方便...
但許多特殊情況我們還是需要 AbsoluteLayout。
AbsoluteLayout 的大小
上面小節都在討論 AbsoluteLayout 內 子元素 的大小和位置,那 AbsoluteLayout 本身的大小呢~?
就像所有的 Visual elements, AbsoluteLayout 也有自己的 HorizontalOptions 和 VerticalOptions 可以設定,初始值為 fill。
若是將 HorizontalOptions 和 VerticalOptions 設定為 center,可以發現 AbsoluteLayout 會依照 內容 自動計算其大小。
我們來製作一個簡單的棋盤,同時觀察設定 center 後 AbsoluteLayout 的大小:
public class ChessboardFixedPage : ContentPage { public ChessboardFixedPage() { const double squareSize = 35; AbsoluteLayout absoluteLayout = new AbsoluteLayout { //先做一個黃色的 AbsoluteLayout BackgroundColor = Color.FromRgb(240, 220, 130), HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center }; for (int row = 0; row < 8; row++) { for (int col = 0; col < 8; col++) { // 利用 XOR 二元邏輯運算跳格 if (((row ^ col) & 1) == 0) continue; BoxView boxView = new BoxView { //加入綠色的方塊 Color = Color.FromRgb(0, 64, 0) }; Rectangle rect = new Rectangle( col * squareSize, row * squareSize, squareSize, squareSize ); absoluteLayout.Children.Add(boxView, rect); } } this.Content = absoluteLayout; } }
執行結果 (黃色部分為 AbsoluteLayout 範圍):
Attached bindable properties
承上一小節,如果我們想把棋盤放大跟螢幕大小一樣,有兩種方法可用:
兩個方法都可行,但第二種方法我們只需做一次加入 BoxView 的動作。
承上一小節,如果我們想把棋盤放大跟螢幕大小一樣,有兩種方法可用:
- SizeChanged 時,將適合大小的 BoxView 加入
- 先加入所有 BoxView,在 SizeChanged 時才去改變 BoxView 的大小
兩個方法都可行,但第二種方法我們只需做一次加入 BoxView 的動作。
這種情況下,AbsoluteLayout 提供 SetLayoutBounds() 方法,讓你將 Rectangle 屬性附加上 (Attached) 已存在 AbsoluteLayout 內的物件:
AbsoluteLayout.SetLayoutBounds(view, rect);
*OnPlatform 寫法已更改,請參考此篇文章
來看範例:
原文書 P.346 有解釋其運作原理,有興趣可以翻閱 (都是英文喔~)…
書上這裡有介紹一個 寬高的常數變數 AbsoluteLayout.AutoSize 可以在 Rectangle 內使用,
可設定 width 和 height 為自動尺寸:
var rect = new Rectangle (0, 0, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
來看範例:
public class ChessboardDynamicPage : ContentPage { AbsoluteLayout absoluteLayout; public ChessboardDynamicPage() { //先做一個黃色的 AbsoluteLayout absoluteLayout = new AbsoluteLayout { BackgroundColor = Color.FromRgb(240, 220, 130), HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center }; //一口氣加入 32 個 BoxView,但先不帶入 rect 參數 for (int i = 0; i < 32; i++) { BoxView boxView = new BoxView { Color = Color.FromRgb(0, 64, 0) }; absoluteLayout.Children.Add(boxView); } ContentView contentView = new ContentView { Content = absoluteLayout }; //加入 SizeChanged 事件 contentView.SizeChanged += OnContentViewSizeChanged; this.Padding = new Thickness(5, Device.OnPlatform(25, 5, 5), 5, 5); this.Content = contentView; } void OnContentViewSizeChanged(object sender, EventArgs args) { ContentView contentView = (ContentView)sender; //為了讓方塊適應手機 portrait 或 landscape 方向,大小用算的 double squareSize = Math.Min(contentView.Width, contentView.Height) / 8; int index = 0; //取出所有 BoxView 並利用 SetLayoutBounds 附加(Attatched) rect 參數 for (int row = 0; row < 8; row++) { for (int col = 0; col < 8; col++) { // Skip every other square. if (((row ^ col) & 1) == 0) continue; View view = absoluteLayout.Children[index]; Rectangle rect = new Rectangle( col * squareSize, //x row * squareSize, //y squareSize, //width squareSize //height ); //附加 rect !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AbsoluteLayout.SetLayoutBounds(view, rect); index++; } } } }
原文書 P.346 有解釋其運作原理,有興趣可以翻閱 (都是英文喔~)…
書上這裡有介紹一個 寬高的常數變數 AbsoluteLayout.AutoSize 可以在 Rectangle 內使用,
可設定 width 和 height 為自動尺寸:
var rect = new Rectangle (0, 0, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。