Bagikan melalui


Xamarin.Forms BoxView

BoxView merender persegi panjang sederhana dari lebar, tinggi, dan warna tertentu. Anda dapat menggunakan BoxView untuk dekorasi, grafis dasar, dan untuk interaksi dengan pengguna melalui sentuhan.

Karena Xamarin.Forms tidak memiliki sistem grafis vektor bawaan, BoxView membantu mengkompensasi. Beberapa program sampel yang dijelaskan dalam artikel ini menggunakan BoxView untuk merender grafik. BoxView dapat berukuran menyerupai garis lebar dan ketebalan tertentu, lalu diputar oleh sudut apa pun menggunakan Rotation properti .

Meskipun BoxView dapat meniru grafik sederhana, Anda mungkin ingin menyelidiki Menggunakan SkiaSharp untuk Xamarin.Forms persyaratan grafis yang lebih canggih.

Mengatur Warna dan Ukuran BoxView

Biasanya Anda akan mengatur properti berikut dari BoxView:

Properti Color berjenis Color; properti dapat diatur ke nilai apa pun Color , termasuk 141 bidang baca-saja statis dari warna bernama mulai dari alfabet dari AliceBlue ke YellowGreen.

Properti CornerRadius berjenis CornerRadius; properti dapat diatur ke double satu nilai radius sudut seragam, atau CornerRadius struktur yang ditentukan oleh empat double nilai yang diterapkan ke kiri atas, kanan atas, kiri bawah, dan kanan bawah dari BoxView.

Properti WidthRequest dan HeightRequest hanya memainkan peran jika BoxView tidak dibatasi dalam tata letak. Ini adalah kasus ketika kontainer tata letak perlu mengetahui ukuran anak, misalnya, ketika BoxView adalah anak dari sel berukuran otomatis dalam Grid tata letak. A BoxView juga tidak dibatasi ketika HorizontalOptions properti dan VerticalOptions diatur ke nilai selain LayoutOptions.Fill. BoxView Jika tidak dibatasi, tetapi WidthRequest properti dan HeightRequest tidak diatur, maka lebar atau tinggi diatur ke nilai default 40 unit, atau sekitar 1/4 inci pada perangkat seluler.

Properti WidthRequest dan HeightRequest diabaikan jika BoxView dibatasi dalam tata letak, dalam hal ini kontainer tata letak memberlakukan ukurannya sendiri pada BoxView.

BoxView Dapat dibatasi dalam satu dimensi dan tidak dibatasi di dimensi lainnya. Misalnya, jika BoxView adalah anak dari vertikal StackLayout, dimensi BoxView vertikal tidak dibatasi dan dimensi horizontalnya umumnya dibatasi. Tetapi ada pengecualian untuk dimensi horizontal tersebut BoxView : Jika propertinya HorizontalOptions diatur ke sesuatu selain LayoutOptions.Fill, maka dimensi horizontal juga tidak dibatasi. Dimungkinkan juga bagi dirinya sendiri untuk StackLayout memiliki dimensi horizontal yang tidak dibatasi, dalam hal ini BoxView juga akan tidak dibatasi secara horizontal.

Sampel menampilkan satu inci-persegi yang tidak dibatasi BoxView di tengah halamannya:

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

Berikut hasilnya:

Tampilan Kotak Dasar

VerticalOptions Jika properti dan HorizontalOptions dihapus dari BoxView tag atau diatur ke Fill, maka BoxView menjadi dibatasi oleh ukuran halaman, dan diperluas untuk mengisi halaman.

Juga BoxView bisa menjadi anak dari AbsoluteLayout. Dalam hal ini, lokasi dan ukuran BoxView diatur menggunakan LayoutBounds properti yang dapat diikat yang terpasang. dibahas AbsoluteLayout dalam artikel AbsoluteLayout.

Anda akan melihat contoh semua kasus ini dalam program sampel berikut.

Merender Dekorasi Teks

Anda dapat menggunakan BoxView untuk menambahkan beberapa dekorasi sederhana di halaman Anda dalam bentuk garis horizontal dan vertikal. Sampel menunjukkan ini. Semua visual program didefinisikan dalam file MainPage.xaml , yang berisi beberapa Label elemen dan BoxView dalam yang StackLayout ditunjukkan di sini:

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

Semua markup yang mengikuti adalah anak-anak dari StackLayout. Markup ini terdiri dari beberapa jenis elemen dekoratif BoxView yang digunakan dengan Label elemen :

Dekorasi Teks

Header bergaya di bagian atas halaman dicapai dengan AbsoluteLayout anak-anaknya adalah empat BoxView elemen dan Label, yang semuanya ditetapkan lokasi dan ukuran tertentu:

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

Dalam file XAML, AbsoluteLayout diikuti dengan Label teks berformat yang menjelaskan AbsoluteLayout.

Anda dapat menggaris bawahi string teks dengan mengapit dan Label dalam yang nilainya HorizontalOptions diatur ke sesuatu selain Fill.StackLayoutBoxView Lebar StackLayout kemudian diatur oleh lebar Label, yang kemudian memberlakukan lebar tersebut BoxViewpada . yang BoxView ditetapkan hanya tinggi eksplisit:

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

Anda tidak dapat menggunakan teknik ini untuk menggaris bawahi kata-kata individual dalam string teks atau paragraf yang lebih panjang.

Anda juga dapat menggunakan BoxView untuk menyerupai elemen HTML hr (aturan horizontal). Cukup biarkan lebar BoxView ditentukan oleh kontainer induknya, yang dalam hal ini adalah StackLayout:

<BoxView HeightRequest="3" />

Terakhir, Anda dapat menggambar garis vertikal di satu sisi paragraf teks dengan mengapit BoxView dan Label dalam horizontal StackLayout. Dalam hal ini, tingginya BoxView sama dengan tinggi StackLayout, yang diatur oleh tinggi Label:

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

        ···

    </Label>
</StackLayout>

Mencantumkan Warna dengan BoxView

BoxView nyaman untuk menampilkan warna. Program ini menggunakan untuk mencantumkan ListView semua bidang publik statis baca-saja dari Xamarin.FormsColor struktur:

Warna Tampilan Daftar

Program sampel mencakup kelas bernama NamedColor. Konstruktor statis menggunakan pantulan untuk mengakses semua bidang Color struktur dan membuat NamedColor objek untuk masing-masing bidang. Ini disimpan dalam properti statis All :

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

Visual program dijelaskan dalam file XAML. Properti ItemsSource diatur ListView ke properti statis NamedColor.All , yang berarti bahwa ListView menampilkan semua objek individual NamedColor :

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

Objek NamedColor diformat oleh ViewCell objek yang diatur sebagai templat data .ListView Templat ini mencakup BoxView properti yang Color terikat ke Color properti NamedColor objek.

Memainkan Game of Life oleh Subkelas BoxView

The Game of Life adalah automaton seluler yang diciptakan oleh matematikawan John Conway dan dipopulerkan di halaman Ilmiah Amerika pada tahun 1970-an. Pengantar yang baik disediakan oleh artikel Wikipedia Conway's Game of Life.

Program Xamarin.Forms sampel mendefinisikan kelas bernama LifeCell yang berasal dari BoxView. Kelas ini merangkum logika sel individu dalam Game of Life:

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

LifeCellmenambahkan tiga properti lagi ke BoxView: properti dan Row menyimpan posisi sel dalam kisi, dan IsAlive properti Col menunjukkan statusnya. Properti IsAlive juga mengatur Color properti menjadi BoxView hitam jika sel hidup, dan putih jika sel tidak hidup.

LifeCell juga menginstal TapGestureRecognizer untuk memungkinkan pengguna untuk mengalihkan status sel dengan mengetuknya. Kelas menerjemahkan Tapped peristiwa dari pengenal gerakan ke dalam peristiwanya sendiri Tapped .

Program GameOfLife juga mencakup LifeGrid kelas yang merangkum banyak logika permainan, dan MainPage kelas yang menangani visual program. Ini termasuk overlay yang menjelaskan aturan permainan. Berikut adalah program dalam tindakan yang menunjukkan beberapa ratus LifeCell objek di halaman:

Permainan Kehidupan

Membuat Jam Digital

Program sampel membuat 210 BoxView elemen untuk mensimulasikan titik-titik tampilan matriks titik 5 demi 7 kuno. Anda dapat membaca waktu dalam mode potret atau lanskap, tetapi lebih besar dalam lanskap:

Jam Dot-Matrix

File XAML melakukan lebih sedikit daripada membuat instans yang AbsoluteLayout digunakan untuk jam:

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

Segala sesuatu yang lain terjadi dalam file code-behind. Logika tampilan dot-matrix sangat disederhanakan oleh definisi beberapa array yang menjelaskan titik yang sesuai dengan masing-masing dari 10 digit dan titik dua:

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

    ···

}

Bidang-bidang ini disimpulkan dengan array BoxView elemen tiga dimensi untuk menyimpan pola titik untuk enam digit.

Konstruktor membuat semua BoxView elemen untuk digit dan titik dua, dan juga menginisialisasi Color properti BoxView elemen untuk titik dua:

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

    ···

}

Program ini menggunakan fitur AbsoluteLayoutposisi relatif dan ukuran . Lebar dan tinggi masing-masing BoxView diatur ke nilai pecahan, khususnya 85% dari 1 dibagi dengan jumlah titik horizontal dan vertikal. Posisi juga diatur ke nilai pecahan.

Karena semua posisi dan ukuran relatif terhadap ukuran AbsoluteLayouttotal , SizeChanged handler untuk halaman hanya perlu mengatur HeightRequest dari AbsoluteLayout:

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

    ···

}

Lebar AbsoluteLayout diatur secara otomatis karena membentang ke lebar penuh halaman.

Kode akhir di MainPage kelas memproses panggilan balik timer dan mewarnai titik-titik dari setiap digit. Definisi array multi-dimensi di awal file code-behind membantu menjadikan logika ini sebagai bagian paling sederhana dari program:

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

Membuat Jam Analog

Jam dot-matrix mungkin tampaknya merupakan aplikasi yang jelas dari BoxView, tetapi BoxView elemen juga mampu mewujudkan jam analog:

Jam BoxView

Semua visual dalam program sampel adalah turunan dari AbsoluteLayout. Elemen-elemen ini berukuran LayoutBounds menggunakan properti terlampir, dan diputar menggunakan Rotation properti .

Tiga BoxView elemen untuk tangan jam dibuat dalam file XAML, tetapi tidak diposisikan atau berukuran:

<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 file code-behind membuat instans 60 BoxView elemen untuk tanda centang di sekitar lingkar jam:

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

    ···

}

Ukuran dan posisi semua BoxView elemen terjadi di SizeChanged handler untuk AbsoluteLayout. Sedikit struktur internal ke kelas yang disebut HandParams menggambarkan ukuran masing-masing dari tiga tangan relatif terhadap ukuran total jam:

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

    ···

 }

Handler SizeChanged menentukan pusat dan radius AbsoluteLayout, lalu ukuran dan posisi 60 BoxView elemen yang digunakan sebagai tanda centang. Perulangan for menyimpulkan dengan mengatur Rotation properti dari masing-masing elemen ini BoxView . Di akhir SizeChanged handler, LayoutHand metode dipanggil untuk mengukur dan memposisikan tiga tangan jam:

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

    ···

}

Metode ini LayoutHand mengukur dan memposisikan setiap tangan untuk mengarah langsung ke posisi 12:00. Di akhir metode, AnchorY properti diatur ke posisi yang sesuai dengan pusat jam. Ini menunjukkan pusat rotasi.

Tangan diputar dalam fungsi panggilan balik timer:

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

Tangan kedua diperlakukan sedikit berbeda: Fungsi pelingan animasi diterapkan untuk membuat gerakan tampak mekanis daripada halus. Pada setiap centang, tangan kedua menarik kembali sedikit dan kemudian melakukan overshoot tujuannya. Sedikit kode ini menambah banyak realisme gerakan.