Xamarin.Forms BoxView

Ukázka stažení Stažení ukázky

BoxView vykreslí jednoduchý obdélník zadané šířky, výšky a barvy. Můžete použít BoxView pro dekorace, základní grafiku a pro interakci s uživatelem přes dotykové ovládání.

Vzhledem Xamarin.Forms k tomu, že nemá integrovaný systém vektorových grafik, BoxView pomáhá kompenzovat. Některé z ukázkových programů popsaných v tomto článku se používají BoxView pro vykreslování grafiky. BoxViewVelikost může být podobná čáře konkrétní šířky a tloušťky a následně otočena jakýmkoli úhlem pomocí Rotation Vlastnosti.

I když BoxView mohou napodobovat jednoduché grafiky, můžete chtít prozkoumat Using SkiaSharp in Xamarin.Forms podrobnější požadavky na grafiku.

Nastavení BoxView barvy a velikosti

Obvykle nastavíte následující vlastnosti BoxView :

ColorVlastnost je typu Color ; vlastnost může být nastavena na libovolnou Color hodnotu, včetně statických polí jen pro čtení, která 141 jsou v abecedním pořadí od AliceBlue do YellowGreen .

CornerRadiusVlastnost je typu CornerRadius ; vlastnost může být nastavena na jedinou double hodnotu poloměru horního rohu nebo na CornerRadius strukturu definovanou čtyřmi double hodnotami, které jsou aplikovány na levý horní, pravý horní, dolní levý a pravý dolní okraj BoxView .

WidthRequestVlastnosti a HeightRequest hrají pouze roli, pokud BoxView je v rozložení WidthRequest . Jedná se o případ, kdy kontejner rozložení potřebuje znát velikost dítěte, například, když BoxView je objekt podřízenosti buňky s automatickou velikostí v Grid rozložení. BoxViewJe také bez omezení HorizontalOptions , pokud VerticalOptions jsou vlastnosti a vlastností nastaveny na jiné hodnoty než LayoutOptions.Fill . Pokud BoxView je neomezená, ale WidthRequest vlastnosti a nejsou HeightRequest nastaveny, Šířka nebo výška se nastaví na výchozí hodnoty 40 jednotek nebo přibližně na 1/4 palce na mobilních zařízeních.

WidthRequestVlastnosti a HeightRequest jsou ignorovány, pokud BoxView je WidthRequest v rozložení, v takovém případě kontejner rozložení ukládá svoji vlastní velikost na BoxView .

Je BoxView možné omezit v jedné dimenzi a Neomezovat v druhé. Například pokud BoxView je podřízenou položkou svislé StackLayout , svislá dimenze BoxView je neomezená a její vodorovná dimenze je obecně omezená. Existují však výjimky pro tuto vodorovnou dimenzi: Pokud BoxViewHorizontalOptions vlastnost nastavenou na jinou hodnotu než LayoutOptions.Fill , je vodorovná dimenze také neomezená. Je také možné StackLayout , že samotný má neomezenou vodorovnou dimenzi, v takovém případě BoxView bude také horizontálně neomezená.

Ukázka BasicBoxView zobrazí v středu své stránky neomezenou mocninu o velikosti jednoho palce.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:BasicBoxView"
             x:Class="BasicBoxView.MainPage">

    <BoxView Color="CornflowerBlue"
             CornerRadius="10"
             WidthRequest="160"
             HeightRequest="160"
             VerticalOptions="Center"
             HorizontalOptions="Center" />

</ContentPage>

Výsledek:

Basic BoxView

Pokud VerticalOptionsHorizontalOptions jsou vlastnosti a odebrány ze BoxView značky nebo jsou nastaveny na Fill , pak BoxView dojde k omezení velikosti stránky a rozbalí se, aby vyplnila stránku.

BoxViewMůže být také podřízenou položkou AbsoluteLayout . V takovém případě je umístění i velikost BoxView nastaveny pomocí LayoutBounds připojené vlastnosti BIND. AbsoluteLayoutJe popsána v článku AbsoluteLayout.

Příklady všech těchto případů najdete v ukázkových programech, které následují.

Vykreslování dekorace textu

Můžete použít BoxView k přidání některých jednoduchých dekorace na stránky ve formě vodorovných a svislých čar. Tento příklad demonstruje TextDecoration Sample. Všechny vizuály programu jsou definovány v souboru MainPage. XAML , který obsahuje několik elementů a, které jsou BoxViewStackLayout zde uvedeny:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:TextDecoration"
             x:Class="TextDecoration.MainPage">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS" Value="0, 20, 0, 0" />
        </OnPlatform>
    </ContentPage.Padding>

    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="BoxView">
                <Setter Property="Color" Value="Black" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ScrollView Margin="15">
        <StackLayout>

            ···

        </StackLayout>
    </ScrollView>
</ContentPage>

Všechny následující značky jsou podřízené objekty StackLayout . Tento kód se skládá z několika typů dekorativních prvků, které BoxView jsou použity s Label prvkem:

Dekorace textu dekorující

Styl tohoto příznaku v horní části stránky se dosáhne pomocí AbsoluteLayout , jehož podřízené položky jsou čtyři BoxView prvky a a, ke Label kterým jsou přiřazena konkrétní umístění a velikosti:

<AbsoluteLayout>
    <BoxView AbsoluteLayout.LayoutBounds="0, 10, 200, 5" />
    <BoxView AbsoluteLayout.LayoutBounds="0, 20, 200, 5" />
    <BoxView AbsoluteLayout.LayoutBounds="10, 0, 5, 65" />
    <BoxView AbsoluteLayout.LayoutBounds="20, 0, 5, 65" />
    <Label Text="Stylish Header"
           FontSize="24"
           AbsoluteLayout.LayoutBounds="30, 25, AutoSize, AutoSize"/>
</AbsoluteLayout>

V souboru XAML AbsoluteLayout je následován a Label formátovaný text, který popisuje AbsoluteLayout .

Textový řetězec lze podtrhnout uzavřením Label a BoxView v StackLayout , jehož HorizontalOptions hodnota je nastavena na jinou hodnotu než Fill . Šířka ovládacího panelu StackLayout se pak řídí šířkou Label , která poté ukládá tuto šířku na BoxView . BoxViewJe přiřazena pouze explicitní Výška:

<StackLayout HorizontalOptions="Center">
    <Label Text="Underlined Text"
           FontSize="24" />
    <BoxView HeightRequest="2" />
</StackLayout>

Tuto techniku nelze použít pro podtržení jednotlivých slov v rámci delších textových řetězců nebo odstavců.

Je také možné použít BoxView pro podobnou hr prvku HTML (horizontální pravidlo). Stačí, když zadáte šířku BoxView určené jeho nadřazeným kontejnerem, což je v tomto případě StackLayout :

<BoxView HeightRequest="3" />

Nakonec můžete nakreslit svislou čáru na jednu stranu textu odstavce, a to uzavřením do BoxViewLabel vodorovného StackLayout . V tomto případě je výška je BoxView stejná jako výška StackLayout , která se řídí výškou Label :

<StackLayout Orientation="Horizontal">
    <BoxView WidthRequest="4"
             Margin="0, 0, 10, 0" />
    <Label>

        ···

    </Label>
</StackLayout>

Seznam barev pomocí BoxView

BoxViewJe vhodný pro zobrazení barev. Tento program používá ListView k vypsání všech veřejných statických polí jen pro čtení ve Xamarin.FormsColor struktuře:

Barvy ListView ListView

Program ListViewColors obsahuje třídu s názvem . Statický konstruktor používá reflexi pro přístup ke všem polím Color struktury a k vytvoření NamedColor objektu pro každý z nich. Jsou uloženy ve statické All vlastnosti:

public class NamedColor
{
    // Instance members.
    private NamedColor()
    {
    }

    public string Name { private set; get; }

    public string FriendlyName { private set; get; }

    public Color Color { private set; get; }

    public string RgbDisplay { private set; get; }

    // Static members.
    static NamedColor()
    {
        List<NamedColor> all = new List<NamedColor>();
        StringBuilder stringBuilder = new StringBuilder();

        // Loop through the public static fields of the Color structure.
        foreach (FieldInfo fieldInfo in typeof(Color).GetRuntimeFields ())
        {
            if (fieldInfo.IsPublic &&
                fieldInfo.IsStatic &&
                fieldInfo.FieldType == typeof (Color))
            {
                // Convert the name to a friendly name.
                string name = fieldInfo.Name;
                stringBuilder.Clear();
                int index = 0;

                foreach (char ch in name)
                {
                    if (index != 0 && Char.IsUpper(ch))
                    {
                        stringBuilder.Append(' ');
                    }
                    stringBuilder.Append(ch);
                    index++;
                }

                // Instantiate a NamedColor object.
                Color color = (Color)fieldInfo.GetValue(null);

                NamedColor namedColor = new NamedColor
                {
                    Name = name,
                    FriendlyName = stringBuilder.ToString(),
                    Color = color,
                    RgbDisplay = String.Format("{0:X2}-{1:X2}-{2:X2}",
                                               (int)(255 * color.R),
                                               (int)(255 * color.G),
                                               (int)(255 * color.B))
                };

                // Add it to the collection.
                all.Add(namedColor);
            }
        }
        all.TrimExcess();
        All = all;
    }

    public static IList<NamedColor> All { private set; get; }
}

Vizuály programu jsou popsány v souboru XAML. ItemsSourceVlastnost ListView je nastavena na statickou NamedColor.All vlastnost, což znamená, že ListView zobrazí všechny jednotlivé NamedColor objekty:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ListViewColors"
             x:Class="ListViewColors.MainPage">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS" Value="10, 20, 10, 0" />
            <On Platform="Android, UWP" Value="10, 0" />
        </OnPlatform>
    </ContentPage.Padding>

    <ListView SeparatorVisibility="None"
              ItemsSource="{x:Static local:NamedColor.All}">
        <ListView.RowHeight>
            <OnPlatform x:TypeArguments="x:Int32">
                <On Platform="iOS, Android" Value="80" />
                <On Platform="UWP" Value="90" />
            </OnPlatform>
        </ListView.RowHeight>

        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <ContentView Padding="5">
                        <Frame OutlineColor="Accent"
                               Padding="10">
                            <StackLayout Orientation="Horizontal">
                                <BoxView Color="{Binding Color}"
                                         WidthRequest="50"
                                         HeightRequest="50" />
                                <StackLayout>
                                    <Label Text="{Binding FriendlyName}"
                                           FontSize="22"
                                           VerticalOptions="StartAndExpand" />
                                    <Label Text="{Binding RgbDisplay, StringFormat='RGB = {0}'}"
                                           FontSize="16"
                                           VerticalOptions="CenterAndExpand" />
                                </StackLayout>
                            </StackLayout>
                        </Frame>
                    </ContentView>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>

NamedColorObjekty jsou formátovány ViewCell objektem, který je nastaven jako šablona dat pro ListView . Tato šablona obsahuje, BoxView jejíž Color vlastnost je svázána s Color vlastností NamedColor objektu.

Hraní herního života pomocí BoxView podtříd

Hra životního cyklu je mobilní Automation vymysleli od mathematician Jan Conwayův kodex a oblíbená na stránkách vědecké Ameriky v 1970s. Dobrá příručka je k dispozici ve hře Wikipedii article Conwayův kodex pro životní cyklus.

Program Xamarin.FormsXamarin.Forms definuje třídu s názvem , která je odvozena z BoxView . Tato třída zapouzdřuje logiku jednotlivých buněk ve hře:

class LifeCell : BoxView
{
    bool isAlive;

    public event EventHandler Tapped;

    public LifeCell()
    {
        BackgroundColor = Color.White;

        TapGestureRecognizer tapGesture = new TapGestureRecognizer();
        tapGesture.Tapped += (sender, args) =>
        {
            Tapped?.Invoke(this, EventArgs.Empty);
        };
        GestureRecognizers.Add(tapGesture);
    }

    public int Col { set; get; }

    public int Row { set; get; }

    public bool IsAlive
    {
        set
        {
            if (isAlive != value)
            {
                isAlive = value;
                BackgroundColor = isAlive ? Color.Black : Color.White;
            }
        }
        get
        {
            return isAlive;
        }
    }
}

LifeCell Přidá tři další vlastnosti k BoxView : Col vlastnosti a Row ukládají pozici buňky v mřížce a IsAlive vlastnost indikuje její stav. IsAliveVlastnost také nastaví Color vlastnost BoxView na černou, pokud je buňka aktivní a bílá, pokud buňka není aktivní.

LifeCell nainstaluje také TapGestureRecognizer , aby uživatel mohl přepnout stav buněk klepnutím na ně. Třída překládá Tapped událost z nástroje pro rozpoznávání gest na vlastní Tapped událost.

Program GameOfLife zahrnuje také třídu, která zapouzdřuje většinu logiky hry, a MainPage třídu, která zpracovává vizuály programu. Mezi ně patří překrytí, které popisuje pravidla hry. Tady je program v akci, na kterém je vidět několik stovek LifeCell objektů:

životního cyklu životnosti

Vytváření digitálních hodin

Program DotMatrixClock vytvoří prvky 210 pro simulaci teček ze starého displeje s tečkou 5-po 7. Čas si můžete přečíst v režimu na výšku nebo na šířku, ale je větší na šířku:

Jehličkovátečka – matice

Soubor XAML má poněkud více instancí než vytvoření instance AbsoluteLayout používané pro hodiny:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DotMatrixClock"
             x:Class="DotMatrixClock.MainPage"
             Padding="10"
             SizeChanged="OnPageSizeChanged">

    <AbsoluteLayout x:Name="absoluteLayout"
                    VerticalOptions="Center" />
</ContentPage>

Všechno ostatní dojde v souboru kódu na pozadí. Logika zobrazení jehličkové matice je výrazně zjednodušená definicí několika polí, která popisují tečky odpovídající každé z 10 číslic a dvojtečkou:

public partial class MainPage : ContentPage
{
    // Total dots horizontally and vertically.
    const int horzDots = 41;
    const int vertDots = 7;

    // 5 x 7 dot matrix patterns for 0 through 9.
    static readonly int[, ,] numberPatterns = new int[10, 7, 5]
    {
        {
            { 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 1, 1}, { 1, 0, 1, 0, 1},
            { 1, 1, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
        },
        {
            { 0, 0, 1, 0, 0}, { 0, 1, 1, 0, 0}, { 0, 0, 1, 0, 0}, { 0, 0, 1, 0, 0},
            { 0, 0, 1, 0, 0}, { 0, 0, 1, 0, 0}, { 0, 1, 1, 1, 0}
        },
        {
            { 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0},
            { 0, 0, 1, 0, 0}, { 0, 1, 0, 0, 0}, { 1, 1, 1, 1, 1}
        },
        {
            { 1, 1, 1, 1, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 1, 0, 0}, { 0, 0, 0, 1, 0},
            { 0, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
        },
        {
            { 0, 0, 0, 1, 0}, { 0, 0, 1, 1, 0}, { 0, 1, 0, 1, 0}, { 1, 0, 0, 1, 0},
            { 1, 1, 1, 1, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 0, 1, 0}
        },
        {
            { 1, 1, 1, 1, 1}, { 1, 0, 0, 0, 0}, { 1, 1, 1, 1, 0}, { 0, 0, 0, 0, 1},
            { 0, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
        },
        {
            { 0, 0, 1, 1, 0}, { 0, 1, 0, 0, 0}, { 1, 0, 0, 0, 0}, { 1, 1, 1, 1, 0},
            { 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
        },
        {
            { 1, 1, 1, 1, 1}, { 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 1, 0, 0},
            { 0, 1, 0, 0, 0}, { 0, 1, 0, 0, 0}, { 0, 1, 0, 0, 0}
        },
        {
            { 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0},
            { 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
        },
        {
            { 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 1},
            { 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0}, { 0, 1, 1, 0, 0}
        },
    };

    // Dot matrix pattern for a colon.
    static readonly int[,] colonPattern = new int[7, 2]
    {
        { 0, 0 }, { 1, 1 }, { 1, 1 }, { 0, 0 }, { 1, 1 }, { 1, 1 }, { 0, 0 }
    };

    // BoxView colors for on and off.
    static readonly Color colorOn = Color.Red;
    static readonly Color colorOff = new Color(0.5, 0.5, 0.5, 0.25);

    // Box views for 6 digits, 7 rows, 5 columns.
    BoxView[, ,] digitBoxViews = new BoxView[6, 7, 5];

    ···

}

Tato pole se dokončí trojrozměrným polem BoxView prvků pro uložení vzorů teček pro šest číslic.

Konstruktor vytvoří všechny BoxView prvky pro číslice a dvojtečku a také inicializuje Color vlastnost BoxView prvků dvojtečky:

public partial class MainPage : ContentPage
{

    ···

    public MainPage()
    {
        InitializeComponent();

        // BoxView dot dimensions.
        double height = 0.85 / vertDots;
        double width = 0.85 / horzDots;

        // Create and assemble the BoxViews.
        double xIncrement = 1.0 / (horzDots - 1);
        double yIncrement = 1.0 / (vertDots - 1);
        double x = 0;

        for (int digit = 0; digit < 6; digit++)
        {
            for (int col = 0; col < 5; col++)
            {
                double y = 0;

                for (int row = 0; row < 7; row++)
                {
                    // Create the digit BoxView and add to layout.
                    BoxView boxView = new BoxView();
                    digitBoxViews[digit, row, col] = boxView;
                    absoluteLayout.Children.Add(boxView,
                                                new Rectangle(x, y, width, height),
                                                AbsoluteLayoutFlags.All);
                    y += yIncrement;
                }
                x += xIncrement;
            }
            x += xIncrement;

            // Colons between the hours, minutes, and seconds.
            if (digit == 1 || digit == 3)
            {
                int colon = digit / 2;

                for (int col = 0; col < 2; col++)
                {
                    double y = 0;

                    for (int row = 0; row < 7; row++)
                    {
                        // Create the BoxView and set the color.
                        BoxView boxView = new BoxView
                            {
                                Color = colonPattern[row, col] == 1 ?
                                            colorOn : colorOff
                            };
                        absoluteLayout.Children.Add(boxView,
                                                    new Rectangle(x, y, width, height),
                                                    AbsoluteLayoutFlags.All);
                        y += yIncrement;
                    }
                    x += xIncrement;
                }
                x += xIncrement;
            }
        }

        // Set the timer and initialize with a manual call.
        Device.StartTimer(TimeSpan.FromSeconds(1), OnTimer);
        OnTimer();
    }

    ···

}

Tento program používá funkci relativního umístění a velikosti AbsoluteLayout . Šířka a výška každého z nich BoxView je nastavená na desetinné hodnoty, konkrétně 85% z 1 dělené počtem vodorovných a svislých teček. Pozice jsou také nastaveny na desetinné hodnoty.

Vzhledem k tomu, že všechny pozice a velikosti jsou relativní vzhledem k celkové velikosti AbsoluteLayout , SizeChanged obslužná rutina stránky musí nastavit pouze HeightRequestAbsoluteLayout :

public partial class MainPage : ContentPage
{

    ···

    void OnPageSizeChanged(object sender, EventArgs args)
    {
        // No chance a display will have an aspect ratio > 41:7
        absoluteLayout.HeightRequest = vertDots * Width / horzDots;
    }

    ···

}

Šířka AbsoluteLayout je automaticky nastavena, protože je roztažena k celé šířce stránky.

Konečný kód ve MainPage třídě zpracovává zpětné volání časovače a barevně tečky každé číslice. Definice multidimenzionálních polí na začátku souboru s kódem na pozadí usnadňuje tuto logiku nejjednodušší část programu:

public partial class MainPage : ContentPage
{

    ···

    bool OnTimer()
    {
        DateTime dateTime = DateTime.Now;

        // Convert 24-hour clock to 12-hour clock.
        int hour = (dateTime.Hour + 11) % 12 + 1;

        // Set the dot colors for each digit separately.
        SetDotMatrix(0, hour / 10);
        SetDotMatrix(1, hour % 10);
        SetDotMatrix(2, dateTime.Minute / 10);
        SetDotMatrix(3, dateTime.Minute % 10);
        SetDotMatrix(4, dateTime.Second / 10);
        SetDotMatrix(5, dateTime.Second % 10);
        return true;
    }

    void SetDotMatrix(int index, int digit)
    {
        for (int row = 0; row < 7; row++)
            for (int col = 0; col < 5; col++)
            {
                bool isOn = numberPatterns[digit, row, col] == 1;
                Color color = isOn ? colorOn : colorOff;
                digitBoxViews[index, row, col].Color = color;
            }
    }
}

Vytváření analogových hodin

Hodiny jehličkové tabulky můžou být zjevné aplikace BoxView , ale BoxView prvky jsou také schopné realizovat analogové hodiny:

Hodiny BoxView hodinBoxView hodin BoxView

Všechny vizuály v programu BoxViewClock jsou podřízené . Tyto prvky mají velikost pomocí LayoutBounds připojené vlastnosti a jsou otočeny pomocí Rotation Vlastnosti.

Tři BoxView prvky pro ruce s hodinami jsou vytvořeny v souboru XAML, ale ne v umístění nebo velikosti:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:BoxViewClock"
             x:Class="BoxViewClock.MainPage">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS" Value="0, 20, 0, 0" />
        </OnPlatform>
    </ContentPage.Padding>

    <AbsoluteLayout x:Name="absoluteLayout"
                    SizeChanged="OnAbsoluteLayoutSizeChanged">

        <BoxView x:Name="hourHand"
                 Color="Black" />

        <BoxView x:Name="minuteHand"
                 Color="Black" />

        <BoxView x:Name="secondHand"
                 Color="Black" />
    </AbsoluteLayout>
</ContentPage>

Konstruktor souboru kódu na pozadí vytváří instanci BoxView elementů 60 pro značky zaškrtnutí kolem obvodu hodin:

public partial class MainPage : ContentPage
{

    ···

    BoxView[] tickMarks = new BoxView[60];

    public MainPage()
    {
        InitializeComponent();

        // Create the tick marks (to be sized and positioned later).
        for (int i = 0; i < tickMarks.Length; i++)
        {
            tickMarks[i] = new BoxView { Color = Color.Black };
            absoluteLayout.Children.Add(tickMarks[i]);
        }

        Device.StartTimer(TimeSpan.FromSeconds(1.0 / 60), OnTimerTick);
    }

    ···

}

Velikost a umístění všech BoxView prvků se vyskytnou v SizeChanged obslužné rutině pro AbsoluteLayout . Malá vnitřní struktura třídy s názvem popisuje velikost každé ze tří rukou vzhledem k celkové HandParams velikosti hodin:

public partial class MainPage : ContentPage
{
    // Structure for storing information about the three hands.
    struct HandParams
    {
        public HandParams(double width, double height, double offset) : this()
        {
            Width = width;
            Height = height;
            Offset = offset;
        }

        public double Width { private set; get; }   // fraction of radius
        public double Height { private set; get; }  // ditto
        public double Offset { private set; get; }  // relative to center pivot
    }

    static readonly HandParams secondParams = new HandParams(0.02, 1.1, 0.85);
    static readonly HandParams minuteParams = new HandParams(0.05, 0.8, 0.9);
    static readonly HandParams hourParams = new HandParams(0.125, 0.65, 0.9);

    ···

 }

Obslužná rutina určuje střed a poloměr a pak velikost a umístění 60 prvků použitých SizeChangedAbsoluteLayout jako BoxView značky. Smyčka for končí nastavením vlastnosti každého z těchto RotationBoxView prvků. Na konci obslužné rutiny je volána metoda pro nastavení velikosti a umístění tří rukou SizeChangedLayoutHand hodin:

public partial class MainPage : ContentPage
{

    ···

    void OnAbsoluteLayoutSizeChanged(object sender, EventArgs args)
    {
        // Get the center and radius of the AbsoluteLayout.
        Point center = new Point(absoluteLayout.Width / 2, absoluteLayout.Height / 2);
        double radius = 0.45 * Math.Min(absoluteLayout.Width, absoluteLayout.Height);

        // Position, size, and rotate the 60 tick marks.
        for (int index = 0; index < tickMarks.Length; index++)
        {
            double size = radius / (index % 5 == 0 ? 15 : 30);
            double radians = index * 2 * Math.PI / tickMarks.Length;
            double x = center.X + radius * Math.Sin(radians) - size / 2;
            double y = center.Y - radius * Math.Cos(radians) - size / 2;
            AbsoluteLayout.SetLayoutBounds(tickMarks[index], new Rectangle(x, y, size, size));
            tickMarks[index].Rotation = 180 * radians / Math.PI;
        }

        // Position and size the three hands.
        LayoutHand(secondHand, secondParams, center, radius);
        LayoutHand(minuteHand, minuteParams, center, radius);
        LayoutHand(hourHand, hourParams, center, radius);
    }

    void LayoutHand(BoxView boxView, HandParams handParams, Point center, double radius)
    {
        double width = handParams.Width * radius;
        double height = handParams.Height * radius;
        double offset = handParams.Offset;

        AbsoluteLayout.SetLayoutBounds(boxView,
            new Rectangle(center.X - 0.5 * width,
                          center.Y - offset * height,
                          width, height));

        // Set the AnchorY property for rotations.
        boxView.AnchorY = handParams.Offset;
    }

    ···

}

Metoda LayoutHand velikostí a umístěním každé ruky, aby odkazla přímo na pozici 12:00. Na konci metody je vlastnost nastavená na pozici odpovídající AnchorY středu hodin. Označuje střed rotace.

Ruce se otáčí ve funkci zpětného volání časovače:

public partial class MainPage : ContentPage
{

    ···

    bool OnTimerTick()
    {
        // Set rotation angles for hour and minute hands.
        DateTime dateTime = DateTime.Now;
        hourHand.Rotation = 30 * (dateTime.Hour % 12) + 0.5 * dateTime.Minute;
        minuteHand.Rotation = 6 * dateTime.Minute + 0.1 * dateTime.Second;

        // Do an animation for the second hand.
        double t = dateTime.Millisecond / 1000.0;

        if (t < 0.5)
        {
            t = 0.5 * Easing.SpringIn.Ease(t / 0.5);
        }
        else
        {
            t = 0.5 * (1 + Easing.SpringOut.Ease((t - 0.5) / 0.5));
        }

        secondHand.Rotation = 6 * (dateTime.Second + t);
        return true;
    }
}

Na druhé straně se s pohybem zachází trochu jinak: Používá se funkce animace, která umožňuje, aby se pohyb zdál být hladký a nikoli hladký. Při každém odškrtu se druhá ruky trochu vrátí zpět a pak přeřesní svůj cíl. Tento malý fragment kódu přidává hodně do realismu pohybu.