Xamarin.Forms BoxView

Download Sample Örneği indirme

BoxView belirtilen genişlik, yükseklik ve renkte basit bir dikdörtgen oluşturur. Dekorasyon, ilkel grafikler ve dokunarak kullanıcıyla etkileşim için kullanabilirsiniz BoxView .

Xamarin.Forms Yerleşik vektör grafik sistemi olmadığından, BoxView bunu telafi etmeye yardımcı olur. Bu makalede açıklanan örnek programlardan bazıları grafikleri işlemek için kullanılır BoxView . BoxView, belirli bir genişlik ve kalınlıkta bir çizgiye benzeyecek şekilde boyutlandırılabilir ve ardından özelliği kullanılarak herhangi bir açıyla Rotation döndürülebilir.

Basit grafikleri taklit edebilir, ancak BoxView daha karmaşık grafik gereksinimleri için SkiaSharp'ı Xamarin.Forms kullanma hakkında araştırma yapmak isteyebilirsiniz.

BoxView Renk ve Boyutunu Ayarlama

Genellikle aşağıdaki özelliklerini BoxViewayarlarsınız:

  • Color öğesini seçin.
  • CornerRadius öğesini seçin.
  • WidthRequest cihazın genişliğini cihazdan BoxView bağımsız birimler halinde ayarlamak için.
  • HeightRequest öğesinin yüksekliğini ayarlamak için BoxView.

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

CornerRadius özelliği türündedirCornerRadius; özelliği tek double bir tekdüzen köşe yarıçapı değerine veya sol üst, sağ üst, sol alt ve sağ BoxViewalta uygulanan dört double değerle tanımlanan bir CornerRadius yapıya ayarlanabilir.

WidthRequest ve HeightRequest özellikleri yalnızca düzeninde kısıtlanmamışsa BoxView rol oynar. Bu durum, düzen kapsayıcısının çocuğun boyutunu bilmesi gerektiğinde (örneğin, düzende Grid otomatik boyutlandırılmış bir hücrenin alt öğesi olduğundaBoxView) durumdur. ve özellikleri dışındaki değerlere ayarlandığında da A BoxView kısıtlanmamıştır VerticalOptionsHorizontalOptions.LayoutOptions.Fill BoxView kısıtlanmamışsa ancak WidthRequest ve HeightRequest özellikleri ayarlanmamışsa, genişlik veya yükseklik 40 birim veya mobil cihazlarda yaklaşık 1/4 inç varsayılan değerlere ayarlanır.

WidthRequest düzeni kısıtlanmışsaBoxViewve HeightRequest özellikleri yoksayılır ve bu durumda düzen kapsayıcısı üzerinde BoxViewkendi boyutunu uygular.

Bir BoxView , bir boyutta kısıtlanabilir ve diğerinde kısıtlanamaz. Örneğin, dikey bir öğesinin BoxViewStackLayoutalt öğesiyse, öğesinin BoxView dikey boyutu kısıtlanmamıştır ve yatay boyutu genellikle kısıtlanır. Ancak bu yatay boyut için özel durumlar vardır: özelliği dışında LayoutOptions.Fillbir değere ayarlanmışsa BoxViewHorizontalOptions, yatay boyut da kısıtlanmamıştır. Ayrıca, kendisinin kısıtlanmamış bir yatay boyuta sahip olması da mümkündür StackLayout ve bu durumda BoxView da yatay olarak kısıtlanmamış olur.

BasicBoxView örneği, sayfasının ortasında bir inç kareyi sınırlandırılmamış BoxView olarak 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

VerticalOptions ve HorizontalOptions özellikleri etiketinden BoxView kaldırılırsa veya olarak ayarlanırsaFillBoxView, sayfa boyutuyla kısıtlanır ve sayfayı dolduracak şekilde genişletilir.

, BoxView bir öğesinin AbsoluteLayoutde alt öğesi olabilir. Bu durumda, hem konumu hem de boyutu BoxView ekli bağlanabilir özelliği kullanılarak LayoutBounds ayarlanır. AbsoluteLayout, AbsoluteLayout makalesinde ele alınmıştı.

Aşağıdaki örnek programlarda tüm bu durumların örneklerini görürsünüz.

Metin Süslemelerini İşleme

sayfalarınıza yatay ve dikey çizgiler biçiminde bazı basit süslemeler eklemek için öğesini kullanabilirsiniz BoxView . TextDecoration örneği bunu gösterir. Programın tüm görselleri MainPage.xaml dosyasında tanımlanır ve burada gösterilen birkaç Label öğeyi içerir StackLayoutBoxView:

<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şaretlemelerin tümü öğesinin StackLayoutalt öğeleridir. Bu işaretleme, öğesiyle Label kullanılan çeşitli dekoratif BoxView öğe türlerinden oluşur:

Text Decoration

Sayfanın üst kısmındaki şık üst bilgi, alt öğeleri dört BoxView öğe ve tümüne belirli konumlar ve boyutlar atanmış olan bir Labelile AbsoluteLayout elde 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 öğesinin ardından Label öğesini açıklayan AbsoluteLayoutbiçimlendirilmiş bir metin eklenir.

hem hem BoxView de Label değerini dışında Fillbir değere ayarlanmış bir içine alarak bir StackLayoutHorizontalOptions metin dizesinin altını çizebilirsiniz. StackLayout genişliği daha sonra genişliğine göre Labelyönetilir ve ardından bu genişliği üzerinde uygularBoxView. BoxView yalnızca açık bir yükseklik atanır:

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

Bu tekniği, uzun metin dizeleri veya paragraf içindeki tek tek sözcüklerin altını çizmek için kullanamazsınız.

Html (yatay kural) öğesine benzemek için de hr kullanabilirsinizBoxView. Yalnızca öğesinin genişliğinin BoxView üst kapsayıcısı tarafından belirlenmesine izin verin. Bu örnekte :StackLayout

<BoxView HeightRequest="3" />

Son olarak, hem hem Label de BoxView öğesini yatay StackLayoutbir içine alarak metin paragrafının bir tarafına dikey çizgi çizebilirsiniz. Bu durumda, yüksekliği BoxView yüksekliği ile aynıdır StackLayoutve yüksekliği ile aynıdır. Bu, yüksekliğine göre Labelyö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 uygundur. Bu program, yapının tüm genel statik salt okunur alanlarını listelemek Xamarin.FormsColor için bir ListView kullanır:

ListView Colors

ListViewColors programı adlı NamedColorbir sınıf içerir. Statik oluşturucu, yapının tüm alanlarına Color erişmek ve her biri için bir NamedColor nesne oluşturmak için yansıma kullanır. Bunlar statik All özelliğinde 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 NamedColor.All özelliğine ayarlanmış olması, tüm nesneleri tek tek NamedColor görüntülediği ListView anlamına 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>

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

BoxView'ı Alt Sınıflayarak Yaşam Oyununu Oynama

The Game of Life, matematikçi John Conway tarafından icat edilen ve 1970'lerde Scientific American sayfalarında popüler hale getirilen hücresel bir otomatondur. Wikipedia makalesi Conway's Game of Life tarafından iyi bir giriş sağlanır.

Xamarin.FormsGameOfLife programı, öğesinden BoxViewtüretilen adlı LifeCell bir sınıf tanımlar. Bu sınıf, Game of Life'taki 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 öğesine BoxViewüç özellik daha ekler: Col ve Row özellikleri hücrenin konumunu kılavuz içinde depolar ve IsAlive özelliği durumunu gösterir. özelliğiIsAlive, hücre yaşıyorsa özelliğini BoxView siyah, hücre yaşamıyorsa beyaz olarak da ayarlarColor.

LifeCell ayrıca kullanıcının hücrelere dokunarak durumlarını değiştirmesine izin vermek için bir TapGestureRecognizer yükler. sınıfı, olayı hareket tanıyıcısından kendi Tapped olayına çevirirTapped.

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

Game of Life

Dijital Saat Oluşturma

DotMatrixClock programı, eski moda 5'e 7 nokta matrisli bir ekranın noktalarının benzetimini yapmak için 210 BoxView öğe oluşturur. Saati dikey veya yatay modda okuyabilirsiniz, ancak yatay olarak daha büyüktür:

Dot-Matrix Clock

XAML dosyası, saat için kullanılan örneğinden AbsoluteLayout biraz 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 planda kod dosyasında gerçekleşir. Noktalı matris görüntüleme mantığı, 10 basamak ve iki nokta üst üste her birine karşılık gelen noktaları açıklayan çeşitli dizilerin tanımıyla büyük ölçüde basitleştirilmiştir:

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 desenlerini BoxView depolamak için üç boyutlu bir öğe dizisiyle sonuçlanmıştır.

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

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 AbsoluteLayoutkullanır. Her BoxView birinin genişliği ve yüksekliği kesirli değerlere ayarlanır; özellikle 1'in %85'i yatay ve dikey nokta sayısına bölünür. Konumlar da kesirli değerlere ayarlanır.

Tüm konumlar ve boyutlar toplam boyutuna AbsoluteLayoutSizeChanged göre olduğundan, sayfanın işleyicisinin yalnızca öğesini HeightRequest ayarlaması AbsoluteLayoutgerekir:

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

    ···

}

öğesinin AbsoluteLayout genişliği, sayfanın tam genişliğine kadar uzandığından otomatik olarak ayarlanır.

sınıfındaki MainPage son kod zamanlayıcı geri çağırmasını işler ve her bir basamaktaki noktaları renkler. Arka planda kod dosyasının başındaki çok boyutlu dizilerin tanımı, bu mantığın programın en basit parçası haline getirmesine 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

Noktalı matrisli saat, uygulamasının BoxViewbelirgin bir uygulaması gibi görünebilir, ancak BoxView öğeler analog bir saati de gerçekleştirebilir:

BoxView Clock

BoxViewClock programındaki tüm görseller bir AbsoluteLayoutöğesinin alt öğeleridir. Bu öğeler ekli özellik kullanılarak LayoutBounds boyutlandırılır ve özelliği kullanılarak Rotation döndürülür.

Saatin elleri için üç BoxView öğe XAML dosyasında örneği oluşturulur, ancak konumlandırılmaz veya boyutlandırılmaz:

<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 planda kod dosyasının oluşturucusu, saatin çevresi etrafındaki değer çizgileri için 60 BoxView öğeyi 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 BoxView öğelerin boyutlandırması ve konumlandırması işleyicisinde SizeChangedAbsoluteLayoutgerçekleşir. adlı HandParams sınıfın içindeki küçük bir yapı, saatin toplam boyutuna göre üç elin her birinin boyutunu 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 SizeChanged , öğesinin merkezini ve yarıçapını AbsoluteLayoutbelirler ve ardından değer çizgileri olarak kullanılan 60 BoxView öğeyi boyutlandırır ve konumlandırır. Döngü, for bu BoxView öğelerin her birinin özelliğini ayarlayarak Rotation sona erer. İşleyicinin SizeChanged sonunda, LayoutHand saatin üç elini boyutlandırmak ve konumlandırmak 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 eli 12:00 konumuna doğru işaret etmek için boyutlandırıp konumlandırıyor. yönteminin sonunda özelliği, AnchorY saatin merkezine karşılık gelen bir konuma ayarlanır. Bu, döndürme merkezini gösterir.

Eller 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ındı: Hareketin pürüzsüz değil mekanik görünmesi için bir animasyon kolaylaştırma işlevi uygulanır. Her bir kene üzerinde, ikinci el biraz geri çeker ve ardından hedefini aşıyor. Bu küçük kod parçası hareketin gerçekçiliği için çok şey katıyor.