2017/5/9

Xamarin.Forms 教學系列文(十四.貳)Absolute layout - 元素大小自動計算 & XAML & Overlays


學習目標
  • 第二個 Attached bindable propertie - LayoutFlagProperty
  • XAML 寫法
  • Overlays

延續上一小節的棋盤,
還記得當我們在 SizeChanged 時,會先去取得螢幕的寬高,再計算出方塊的大小。忘記了請看上圖...

如果... AbsoluteLayout 能自動幫我們計算方塊的大小...

沒錯... Xamarin 就是這麼貼心... 提供了另一個 Attached bindable propertie  - LayoutFlagProperty

可讓程式依照 比例 自動計算物件的大小。

LayoutFlagProperty 有兩個靜態方法可用:
  • GetLayoutFlags()
  • SetLayoutFlags()

使用 SetLayoutFlags() 時,需先指定要做自動計算的元素,可指定的元素由 AbsoluteLayoutFlags 類別內選擇成員,共八種:
  • None
  • XProportional
  • YProportional
  • PositionProportional
  • WidthProportional
  • HeightProportional
  • SizeProportional
  • All


LayoutFlagProperty 

用法如下:
absoluteLayout.SetLayoutFlags(view, AbsoluteLayoutFlags.All)

或是在新增物件時就帶入:
absoluteLayout.Children.Add(view, rect, AbsoluteLayoutFlags.All)


設定好 LayoutFlagProperty 後,就能在 Rectangle 指派 0 ~ 1 的值當做 比例,讓程式自動去計算在畫面上實際的大小。

來看範例,一樣是上一小節的棋盤程式,但我們使用 LayoutFlagProperty 自動換算方塊的 x, y, width, height:

*Oplatform 寫法已更改,請參考此篇文章
public class ChessboardProportionalPage : ContentPage
{
    AbsoluteLayout absoluteLayout; public ChessboardProportionalPage()
    {
        absoluteLayout = new 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++)
            {
                // Skip every other square. 
                if (((row ^ col) & 1) == 0)
                    continue;

                BoxView boxView = new BoxView
                {
                    Color = Color.FromRgb(0, 64, 0)
                };

                //此處值都為 0 ~ 1
                Rectangle rect = new Rectangle(col / 7.0, // x 
                    row / 7.0, // y 
                    1 / 8.0, // width 
                    1 / 8.0); // height 

                //LayoutFlagsProperty
                absoluteLayout.Children.Add(boxView, rect, AbsoluteLayoutFlags.All);
            }
        }

        ContentView contentView = new ContentView
        {
            Content = absoluteLayout
        };
        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;
        double boardSize = Math.Min(contentView.Width, contentView.Height);
        absoluteLayout.WidthRequest = boardSize;
        absoluteLayout.HeightRequest = boardSize;
    }
}



AbsoluteLayout and XAML

直接看範例了解 AbsoluteLayout 的 XAML 如何寫:
要注意的是 LayoutBounds 的寫法。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="AbsoluteXamlDemo.AbsoluteXamlDemoPage">

    <AbsoluteLayout Padding="50">
        <BoxView Color="Accent"
                 AbsoluteLayout.LayoutBounds="20, 0, 5, 65" />

        <Label Text="Stylish Header" FontSize="24" 
               AbsoluteLayout.LayoutBounds="30, 25, AutoSize, AutoSize" />

    </AbsoluteLayout>
</ContentPage>



Overlays

AbsoluteLayout 最有用的功能之一大概就是這個…覆蓋畫面,並放上 ActivityIndicator (轉圈圈) 或是 ProgressBar (進度條),在等待進度完成前不讓使用者操作其他功能。

直接來看範例,畫面上有一顆 Button,和一個 放有 ProgressBar 的隱藏 ContentView。

XAML://本範例對照原文書有做刪減
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="SimpleOverlay.SimpleOverlayPage">

    <AbsoluteLayout>
        <StackLayout AbsoluteLayout.LayoutBounds="0, 0, 1, 1" 
                     AbsoluteLayout.LayoutFlags="All">
            
            <!-- 觸發按鈕 -->
            <Button Text="Run 5-Second Job" 
                    FontSize="Large" 
                    VerticalOptions="CenterAndExpand"
                    HorizontalOptions="Center" 
                    Clicked="OnButtonClicked" />
            
        </StackLayout>

        <!-- Overlay -->
        <ContentView x:Name="overlay"
                     AbsoluteLayout.LayoutBounds="0, 0, 1, 1" 
                     AbsoluteLayout.LayoutFlags="All" 
                     IsVisible="False" 
                     BackgroundColor="#C0808080" 
                     Padding="10, 0">

            <ProgressBar x:Name="progressBar" VerticalOptions="Center" />
        </ContentView>
    </AbsoluteLayout>
    
</ContentPage>


.cs - 讓 ProgressBar 執行五秒~
public partial class SimpleOverlayPage : ContentPage
{
    public SimpleOverlayPage()
    {
        InitializeComponent();
    }

    void OnButtonClicked(object sender, EventArgs args)
    {
        // 顯示 overlay
        overlay.IsVisible = true;
        TimeSpan duration = TimeSpan.FromSeconds(5);
        DateTime startTime = DateTime.Now;

        // 使用 Timer,每 0.1 秒執行一次
        Device.StartTimer(TimeSpan.FromSeconds(0.1), () =>
        {
            // 計算進度條 現在時間 - 開始時間 / 所有時間
            double progress = (DateTime.Now - startTime).TotalMilliseconds / duration.TotalMilliseconds;
            progressBar.Progress = progress;

            bool continueTimer = progress < 1;
            if (!continueTimer)
            {
                // 隱藏 overlay
                overlay.IsVisible = false;
            }
            return continueTimer;
        });
    }
}


執行結果:


原文書最後有用 AbsoluteLayout 寫兩個有趣的範例,從 p.362 開始~ 有興趣的可自行翻閱~

數位鐘:


不斷移動的 Label:




沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。