Xamarin.Forms BoxView

Örneği İndir Örneği indirme

BoxView belirtilen genişlik, yükseklik ve rengin basit bir dikdörtgenini işler. Süsleme, BoxView ilkel grafikler ve dokunma yoluyla kullanıcıyla etkileşim için kullanabilirsiniz.

Xamarin.Formsyerleşik bir vektör grafik sistemine sahip olduğundan, BoxView dengelemeye yardımcı olur. Bu makalede açıklanan örnek programlardan bazıları grafik işleme BoxView için kullanılır. , belirli bir genişlik ve kalınlık çizgisine benzeyebiliyor ve ardından özelliği kullanılarak herhangi BoxView bir açıyla Rotation döndürülebiliyor.

Basit BoxView grafikleri taklit ediyor olsa da, daha gelişmiş grafik gereksinimleri için araştırma yapmak istiyor Using SkiaSharp in Xamarin.Forms olabilir.

BoxView Rengini ve Boyutunu Ayarlama

Genellikle aşağıdaki özelliklerini BoxView ayarlayabilirsiniz:

özelliği türündedir; özelliği, ile arasında alfabetik olarak değişen adlandırılmış renklerin 141 statik salt okunur alanı da dahil olmak üzere herhangi bir ColorColorColor değere AliceBlueYellowGreen ayarlanır.

özelliği türündedir; özelliği tek bir tekdüz köşe yarıçap değerine veya sol üst, sağ üst, sol alt ve sağ alta uygulanan dört değerle tanımlanan bir yapıya CornerRadiusCornerRadiusdoubleCornerRadiusdoubleBoxView ayarlanmalıdır.

ve WidthRequestHeightRequest özellikleri yalnızca düzeni BoxViewWidthRequest oynar. Bu durum, düzen kapsayıcısı örneğin düzende otomatik olarak boyutlandırilen bir hücrenin alt boyutu olduğunda alt boyutu bilmek zorunda olduğu BoxViewGrid durumdur. ayrıca, BoxView ve özellikleri dışında değerlere HorizontalOptionsVerticalOptions ayarlanırken de sınırlandırilmemiştir. LayoutOptions.Fill sınırlandırilmemişse, ancak ve özellikleri ayarlanmamışsa, genişlik veya yükseklik varsayılan 40 birim veya mobil cihazlarda BoxViewWidthRequest yaklaşık HeightRequest 1/4 inç değerlerine ayarlanır.

düzeninde WidthRequest kısıtlı ise ve özellikleri HeightRequestBoxViewWidthRequest bu durumda düzen kapsayıcısı üzerinde kendi boyutunu BoxView dayatır.

, BoxView bir boyutta kısıtlanmış ve diğeri kısıtlanmamış olabilir. Örneğin, bir dikeyin alt boyutu ise dikey boyutu sınırlandırilmemiştir ve yatay boyutu BoxViewStackLayout genellikle BoxView kısıtlanmış olur. Ancak bu yatay boyut için özel durumlar vardır: özelliği dışında bir değere ayarlanmışsa, yatay boyut BoxViewHorizontalOptions da LayoutOptions.Fill sınırlandırilmemiş olur. Kendisi de sınırlandırlanmamış bir yatay boyuta sahip olabilir, bu durumda da yatay olarak StackLayoutBoxView kısıtlanmamış olur.

BasicBoxView örneği, sayfasının merkezinde sınırlandırilmemiş bir inç kare görüntüler:

<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>

Sonuç şu şekildedir:

Basic BoxView

ve özellikleri etiketten kaldırılırsa veya olarak ayarlanırsa, sayfa boyutuyla kısıtlanmış hale gelir ve sayfayı VerticalOptionsHorizontalOptionsBoxViewFillBoxView dolduracak şekilde genişler.

, BoxView bir alt da AbsoluteLayout olabilir. Bu durumda, hem konumu hem de boyutu BoxView bağlı bağlanabilir özelliği kullanılarak LayoutBounds ayarlanır. , AbsoluteLayoutAbsoluteLayout

Aşağıdaki örnek programlarda tüm bu durumlara örnek olarak yer verilmiştir.

Metin Süslemelerini İşleme

Sayfalarınıza BoxView yatay ve dikey çizgi şeklinde basit süslemeler eklemek için kullanabilirsiniz. TextDecoration örneği bunu gösteriyor. Programın tüm görselleri MainPage.xaml dosyasında tanımlanır ve burada gösterilen dosyasında birkaç ve öğelerini BoxViewStackLayout içerir:

<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>

Aşağıdaki işaretlemenin hepsi, 'nin altında yer StackLayout almaktadır. Bu işaretleme, öğesiyle kullanılan çeşitli BoxView dekoratif öğe türlerinden Label oluşur:

Süslemesi Metin Süslemesi

Sayfanın üst kısmında yer alan üst bilgi, alt öğeleri dört öğe ve her biri belirli konumlar ve boyutlara atanmış olan bir AbsoluteLayoutBoxView ile elde Label edilir:

<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>

XAML dosyasında, AbsoluteLayout dosyasının ardından dosyasını açıklayan Label biçimlendirilmiş bir metni AbsoluteLayout vardır.

Hem hem de değerini dışında bir değere ayarlanmış bir içine alan bir metin dizesinin LabelBoxView alt StackLayoutHorizontalOptions çizgisini Fill çizebilirsiniz. genişliği daha StackLayout sonra genişliğine göre yönetilir ve bu da bu genişliği üzerine Label dayatıyor. BoxView BoxViewyalnızca açık bir yükseklik atanır:

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

Bu tekniği kullanarak daha uzun metin dizeleri veya paragraflar içindeki sözcüklerin alt çizgisini çizebilirsiniz.

Bir HTML BoxView (yatay kural) öğesine benzey etmek için hr de kullanabilirsiniz. Genişliğinin, bu BoxView durumda olan üst kapsayıcısı tarafından StackLayout belirlensin:

<BoxView HeightRequest="3" />

Son olarak, hem hem de sütunlarını yatay bir içine alacak şekilde metin paragraflarının bir tarafına dikey BoxViewLabel çizgi StackLayout çizebilirsiniz. Bu durumda, yüksekliği, yüksekliğiyle aynıdır ve BoxViewStackLayout bu da yüksekliğine göre Label yönetilir:

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

        ···

    </Label>
</StackLayout>

BoxView ile Renkleri Listeleme

, BoxView renkleri görüntülemek için kullanışlıdır. Bu program, ListView yapının tüm genel statik salt okunur alanlarını listelemektedir: Xamarin.FormsColor

ListView Renkleri

ListViewColors programı adlı bir sınıf içerir. Statik oluşturucu, yapının tüm alanlarına erişmek ve her Color biri için bir nesne oluşturmak için yansıma NamedColor kullanır. Bunlar statik özelliğinde All depolanır:

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; }
}

Program görselleri XAML dosyasında açıklanmıştır. ItemsSourceözelliğinin ListView statik özelliğine ayarlanır NamedColor.All ve bu da tek tek tüm nesneleri ListView görüntülemesi anlamına NamedColor gelir:

<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>

Nesneler, NamedColor veri şablonu ViewCell olarak ayarlanmış nesnesi tarafından ListView biçimlendirildi. Bu şablon, BoxView özelliği Color nesnenin özelliğine bağlı olan bir ColorNamedColor içerir.

BoxView'u Alt Sınıfa Göre Oyun Oynama

The Game of Life, matematikçi John Conway tarafından yapılan ve 1970'li yılların Scientific American sayfalarında popüler hale getirildi. Conway's Game of Life ( Conway's Game of Life) wikipedia makalesinde iyi bir giriş sağlanmıştır.

Xamarin.FormsXamarin.Forms programı, sınıfından türeten adlı bir sınıf BoxView tanımlar. Bu sınıf, Yaşam Oyunu'daki tek bir hücrenin mantığını kapsüller:

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 üç özellik daha ekler: ve özellikleri hücrenin konumunu kılavuz içinde BoxViewColRow depolar ve IsAlive özelliği durumunu gösterir. özelliği IsAlive ayrıca hücrenin özelliğini canlıysa siyah, hücre canlı ColorBoxView değilse beyaz olarak ayarlar.

LifeCell ayrıca, kullanıcının TapGestureRecognizer dokunarak hücrelerin durumunu açma/açma izinlerini vermek için bir de yüklenir. sınıfı, olayı Tapped hareket tanıyıcıdan kendi olayına Tapped çevirir.

GameOfLife programı ayrıca oyunun mantığının büyük birını kapsüller ve programın görsellerini ele alan MainPage bir sınıf içerir. Bunlar, oyunun kurallarını açıklayan bir katman içerir. Sayfada birkaç yüz nesne gösteren, uygulamalı LifeCell program şu şekildedir:

Game of LifeGame of

Dijital Saat Oluşturma

DotMatrixClock programı, eski bir 5-7 nokta matrisi görüntüsüne sahip noktaların simülasyonunu yapmak için 210 öğe oluşturur. Saati dikey veya yatay modda okuyabilirsiniz, ancak yatay modda daha büyüktür:

Dot-Matrix Clock

XAML dosyası, saat için kullanılan örneği biraz AbsoluteLayout daha fazlasını yapar:

<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>

Diğer her şey arka arkasındaki kod dosyasında gerçekleşir. Nokta matrisi görüntüleme mantığı, 10 basamak ve iki noktanın her biri için karşılık gelen noktaları açıklayan birkaç dizinin tanımıyla büyük ölçüde basitleştirilir:

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];

    ···

}

Bu alanlar, altı basamak için nokta BoxView desenlerini depolamak için üç boyutlu bir öğe dizisiyle son verir.

Oluşturucu, basamaklar ve iki nokta üst üste için tüm öğeleri oluşturur ve iki BoxView nokta için öğelerin özelliğini de ColorBoxView başlatılır:

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();
    }

    ···

}

Bu program, göreli konumlandırma ve boyutlandırma özelliğini AbsoluteLayout kullanır. Her bir değerin genişliği ve yüksekliği kesirli değerlere BoxView ayarlanmıştır ve 1'in %85'i yatay ve dikey nokta sayısına bölündü. Konumlar da kesirli değerlere ayarlanır.

Tüm konumlar ve boyutlar toplam boyutuna göre olduğundan, sayfa için işleyicinin AbsoluteLayoutSizeChanged yalnızca bir olarak HeightRequestAbsoluteLayout ayarlanmıştır:

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;
    }

    ···

}

genişliğini otomatik AbsoluteLayout olarak ayarlanır çünkü sayfanın tam genişliğine esnetilir.

sınıfındaki son kod MainPage zamanlayıcı geri çağırmasını işler ve her bir basamakta noktaları renklerini gösterir. Arka kısım kod dosyasının başındaki çok boyutlu dizilerin tanımı, bu mantığın programın en basit parçası hale getirile yardımcı olur:

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;
            }
    }
}

Analog Saat Oluşturma

Nokta matrisi saati, uygulamasının belirgin bir uygulaması gibi görünebilir ancak öğeler de bir BoxViewBoxView analog saati fark yapabilir:

BoxView Saat

BoxViewClock programında yer alan tüm görseller bir 'nin en küçükleridir. Bu öğeler ekli özelliği LayoutBounds kullanılarak boyutlandırıldı ve özelliği kullanılarak Rotation döndürülür.

Saatin üç öğenin örneği XAML dosyasında yer BoxView alır, ancak konumlanmaz veya boyutlandırlanmaz:

<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>

Arka arkasındaki kod dosyasının oluşturucusu, saat çevresinde onay işareti işaretleri için 60 BoxView öğenin örneğini oluşturur:

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);
    }

    ···

}

Tüm öğelerin boyutlandırma ve konumlandırması BoxView için SizeChanged işleyicide AbsoluteLayout gerçekleşir. adlı sınıfın içinde yer alan küçük bir yapı, saatin toplam boyutuna göre HandParams üç elden her biri için boyutu açıklar:

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);

    ···

 }

İşleyici, 'nin merkezini ve yarıçapını belirler ve ardından onay işareti olarak kullanılan SizeChangedAbsoluteLayout 60 BoxView öğenin boyutlarını ve konumunu belirler. Döngüsü, for bu öğelerin her biri özelliğini Rotation ayararak son bu sonuca BoxView varıyor. İşleyicinin SizeChanged sonunda, saat LayoutHand üç el boyutunu ve konumunu için yöntemi çağrılır:

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;
    }

    ···

}

Yöntem, LayoutHand her bir el için 12:00 konumunu işaret etmek için boyutları ve konumlarını kullanır. yönteminin sonunda, özelliği AnchorY saatin merkezine karşılık gelen bir konuma ayarlanır. Bu, döndürmenin merkezini gösterir.

El, zamanlayıcı geri çağırma işlevinde döndürülür:

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;
    }
}

İkinci el biraz farklı şekilde ele alınmalıdır: Hareket sorunsuz değil mekanik gibi görünmeye yardımcı olmak için animasyon easing işlevi uygulanır. Her tıkta ikinci el biraz geri çeker ve ardından hedefinin üzerine atlar. Bu küçük kod, hareket gerçekçiliği için çok şey ekler.